Lesson 195 min read

Data Structures: Your Toolbox

November 05, 2026

// TL;DR

Every pattern in this course is really 'which data structure gives me the operation I need cheaply?' This lesson is the consolidated reference. Array/string: index O(1), search O(n). Hash map/set: insert/lookup O(1) average — the workhorse. Stack & queue (deque): push/pop O(1); a monotonic deque gives sliding-window extremes. Linked list: O(1) insert/delete at a known node. Binary heap (heapq): min/max O(1), push/pop O(log n). BST/balanced tree: ordered, search/insert O(log n). Advanced: trie for prefix queries O(len); union-find for connectivity near O(1); Fenwick/segment tree for range query + point update O(log n). Learn the complexity table by heart — interviewers expect you to justify your choice out loud.

Part II of this course goes beyond the core 18 patterns into the structures and algorithms that separate strong candidates from the rest. We start with a consolidating reference, because almost every interview problem reduces to one question: which data structure gives me the operation I need cheaply? Get the trade-offs into your bones and the right tool jumps out before you have even finished reading the prompt.

The idea

A grid of the core data structures used across the course. Array or string: index O(1), search O(n). Hash map or set: insert and lookup O(1) average. Stack and queue: push and pop O(1). Linked list: insert at head O(1). Binary heap: min or max O(1), push and pop O(log n). BST or balanced tree: search and insert O(log n). Trie: prefix lookup O(length). Union-Find: union and find near O(1). Segment or Fenwick tree: range query plus update O(log n). The idea is that each structure trades space for one fast operation, and most interview problems are about picking the structure whose cheap operation matches what the problem needs.

A data structure is a deal: you spend memory and setup time to make one kind of operation fast. Picking well is most of the battle. Here is the whole toolbox, from the everyday structures to the three advanced ones that unlock a surprising number of hard problems.

The everyday structures

Array / string — contiguous memory. Random access by index is O(1); search is O(n); inserting in the middle is O(n) because everything shifts. This is your default container, and in Python a list doubles as a stack.

Hash map / set — the workhorse of coding interviews. Average O(1) insert, delete, and lookup by trading memory for speed. Reach for it whenever you catch yourself about to do a nested loop to “find a matching element” — a hash map usually collapses O(n²) to O(n). (This is the whole Two-Sum insight from Lesson 6.)

Stack & queue — a stack is last-in-first-out (use a list); a queue is first-in-first-out (use collections.deque for O(1) pops from the front). A monotonic stack or deque — one you keep sorted as you push — gives next-greater-element and sliding-window-maximum answers in O(n) (Lessons 4 and 9).

from collections import deque
q = deque([1, 2, 3])
q.append(4)        # push right  — O(1)
q.popleft()        # pop left    — O(1)

Linked list — nodes joined by pointers. The one thing it does better than an array is O(1) insertion or deletion at a node you already hold, with no shifting. The price is no random access (finding the k-th node is O(n)). This is why the reversal and fast/slow-pointer patterns (Lessons 5 and 11) exist.

Binary heap / priority queue — keeps the minimum (or maximum) instantly available. heapq is a min-heap: heappush/heappop are O(log n) and the smallest element is always heap[0] in O(1). Perfect for “top-K”, “k-th largest”, and merging sorted streams (Lesson 14).

import heapq
h = []
heapq.heappush(h, 5); heapq.heappush(h, 1); heapq.heappush(h, 3)
heapq.heappop(h)   # -> 1   (always the smallest)

BST / balanced tree — a binary search tree keeps elements ordered, giving O(log n) search, insert, and delete when balanced (an unbalanced BST degrades to O(n) — a linked list in disguise). Python has no built-in balanced tree; in interviews you either implement BST logic directly (Lesson 13) or reach for a sorted structure like sortedcontainers.SortedList when allowed.

The advanced trio

These three show up in the harder questions, and each is the subject of its own lesson ahead.

Trie (prefix tree) — a tree keyed by characters, so words with shared prefixes share a path. Insert and search a word in O(length), independent of how many words are stored. The tool for autocomplete, dictionary lookups, and prefix queries (Lesson 20).

Union-Find (disjoint set) — answers “are these two things in the same group?” and merges groups, each in near-O(1) time with path compression and union by rank. The go-to for connectivity, counting components, and cycle detection as edges arrive.

class DSU:
    def __init__(self, n):
        self.parent = list(range(n))
    def find(self, x):
        while self.parent[x] != x:
            self.parent[x] = self.parent[self.parent[x]]  # path compression
            x = self.parent[x]
        return x
    def union(self, a, b):
        self.parent[self.find(a)] = self.find(b)

Fenwick tree (BIT) / segment tree — when you need both range queries (sum, min, max over a range) and point updates, and a prefix-sum array is too slow to update, these give both in O(log n). A Fenwick tree is the compact choice for prefix sums with updates:

class Fenwick:
    def __init__(self, n):
        self.tree = [0] * (n + 1)
    def update(self, i, delta):          # add delta at index i (1-based)
        while i < len(self.tree):
            self.tree[i] += delta; i += i & (-i)
    def query(self, i):                  # prefix sum of [1..i]
        s = 0
        while i > 0:
            s += self.tree[i]; i -= i & (-i)
        return s
# Fenwick over [a,b] range sum = query(b) - query(a-1); each op O(log n)

The complexity cheat-sheet

Structure Access / search Insert Delete Notes
Array / string O(1) / O(n) O(n) O(n) index is free, middle is costly
Hash map / set — / O(1) avg O(1) avg O(1) avg worst case O(n) on collisions
Stack / queue (deque) O(n) O(1) O(1) O(1) only at the ends
Linked list O(n) O(1)* O(1)* *at a known node
Binary heap O(1) min/max O(log n) O(log n) not searchable by value
Balanced BST O(log n) O(log n) O(log n) ordered traversal for free
Trie O(len) O(len) O(len) keyed by prefix
Union-Find ~O(1) ~O(1) — connectivity only
Fenwick / segment tree O(log n) O(log n) O(log n) range query + update

When to reach for it

The mapping from problem phrasing to structure is the real skill:

  • “find a pair / have I seen this” → hash map/set.
  • “most recent / matching brackets / next greater” → stack.
  • “shortest unweighted / level by level” → queue.
  • “k largest / smallest / most frequent” → heap.
  • “prefix / starts-with / autocomplete” → trie.
  • “are these connected / number of groups” → union-find.
  • “range sum/min with updates” → Fenwick or segment tree.

Pitfalls

  • Unbalanced BST. A plain BST built from sorted input degrades to O(n). If you need guaranteed O(log n), say “balanced” out loud and use the right structure.
  • Heap is not searchable. A heap gives you the extreme in O(1) but finding or removing an arbitrary element is O(n). Use the right tool for the query you actually have.
  • Reaching for a segment tree too early. If there are no updates, a plain prefix-sum array answers range queries in O(1) with far less code. Only pay for a Fenwick/segment tree when values change.

Recap

Every structure is a trade: memory and setup for one cheap operation. Arrays give O(1) indexing; hash maps give O(1) lookup; stacks/queues give O(1) ends; heaps give the extreme in O(1); BSTs keep order in O(log n); and the advanced trio — trie (prefix O(len)), union-find (connectivity ~O(1)), and Fenwick/segment tree (range + update O(log n)) — unlock the hard problems. Know the table cold and justify your choice out loud; that is exactly the reasoning interviewers are listening for.

Next: Lesson 20 — Tries (Prefix Trees), the first of the advanced structures.