Big-O Cheat Sheet

One page, every complexity number from this track in one place — with the Python-specific gotchas called out explicitly, since Python's convenient syntax can hide the true cost of an operation more easily than a language like Java does. This is meant to be the page you reread the morning of an interview — not a substitute for actually understanding why each number is what it is (that's what the other 28 lessons are for), but a fast way to check your memory or settle a "wait, is that O(n) or O(log n) again?" doubt.

Data Structures

Data structure Access Search Insert Delete Space
list (unsorted)O(1)O(n)O(1) amortized append*, O(n) insert(0, x)O(1) pop(), O(n) pop(0)O(n)
list (sorted)O(1)O(log n) via bisectO(n)O(n)O(n)
Singly linked listO(n)O(n)O(1)**O(1)**O(n)
Doubly linked listO(n)O(n)O(1)**O(1)**O(n)
Stack (Python list)O(n)O(n)O(1) append (push)O(1) popO(n)
Queue (collections.deque)O(n)O(n)O(1) appendleft/append (enqueue)O(1) popleft (dequeue)O(n)
dict / set—O(1) average, O(n) worst***O(1) average, O(n) worst***O(1) average, O(n) worst***O(n)
Binary Search TreeO(log n) average, O(n) worstO(log n) average, O(n) worstO(log n) average, O(n) worstO(log n) average, O(n) worstO(n)
Heap (heapq)O(1) for min onlyO(n) for arbitrary elementO(log n) heappushO(log n) heappopO(n)

* list.append(x) is O(1) amortized (occasional resize copies are spread over many appends), but list.insert(0, x) is O(n) because every existing element has to shift over.
** O(1) only once you already have a reference to the node — finding that position first is the O(n) search above.
*** Worst case only under heavy hash collisions, which Python's hash function makes rare in practice.

The single biggest Python-specific trap in this table: list.pop() (removing the last element) is O(1), but list.pop(0) (removing the first element) is O(n) — every remaining element has to shift left by one. If you find yourself repeatedly popping from the front of a list, that's a direct signal to switch to collections.deque, which makes both ends O(1). This is exactly why the Queue lesson used deque instead of a plain list.

Algorithms

Algorithm Time (average) Time (worst) Space Stable?
Linear searchO(n)O(n)O(1)—
Binary searchO(log n)O(log n)O(1)—
Bubble sortO(n²)O(n²)O(1)Yes
Selection sortO(n²)O(n²)O(1)No
Insertion sortO(n²)O(n²)O(1)Yes
Merge sortO(n log n)O(n log n)O(n)Yes
Quick sortO(n log n)O(n²)O(log n) average, O(n) worstNo
BFSO(V + E)O(V + E)O(V)—
DFSO(V + E)O(V + E)O(V)—
Dijkstra (heapq)O(E log V)O(E log V)O(V + E)—
Kruskal's MSTO(E log E)O(E log E)O(V + E)—
Prim's MST (heapq)O(E log V)O(E log V)O(V + E)—

In real Python code you'd almost always call the built-in sorted() / list.sort() (Timsort, O(n log n) worst case, stable) rather than hand-rolling bubble/selection/insertion/merge/quick sort — this table exists because interviews still test whether you understand how those classic algorithms work under the hood.

Reading "V" and "E": in graph algorithms, V is the number of vertices and E is the number of edges. O(V + E) means the cost scales with the total size of the graph — every vertex and every edge gets visited roughly once.

Common Big-O Growth Rates, Fastest to Slowest

NotationNameTypical example from this track
O(1)ConstantList index access, dict get (average case)
O(log n)LogarithmicBinary search, balanced BST/heap operations
O(n)LinearLinear search, single pass over a list
O(n log n)LinearithmicMerge sort, quick sort (average), Dijkstra/MST with heapq
O(n²)QuadraticBubble/selection/insertion sort, naive nested-loop solutions
O(2ⁿ)ExponentialNaive recursive Fibonacci, brute-force backtracking without pruning
Next up: Knowing the numbers is half the battle — How to Approach a DSA Interview covers the framework for actually applying them under interview pressure.