Complexity Cheatsheet
Big-O is the language of "will this scale". Master the rules of thumb — drop constants, pick the dominant term, separate time and space — and you can predict whether a function is fast enough before running it.
Big-O patterns by data structure and operation
EXAMPLE
# ===== 1) Notation ===== # O(f(n)) upper bound (worst case) # Ω(f(n)) lower bound (best case) # Θ(f(n)) tight bound (worst + best are same order) # We care about O for capacity planning; Θ for accurate descriptions. # ===== 2) Rules ===== # - Drop CONSTANTS: 3n + 5 -> O(n) # - Drop LOWER ORDER: n^2 + n -> O(n^2) # - Loops MULTIPLY: nested for loops over n -> O(n^2) # - Sequential additions ADD; the largest term wins: O(n) + O(log n) = O(n) # - Recurrences: use master theorem (see dsa/divide lesson) # ===== 3) Common complexities (sorted slowest growth first) ===== # O(1) constant # O(log n) halving each step (binary search) # O(sqrt n) rare; some number-theoretic algorithms # O(n) single pass # O(n log n) sorting; divide-and-conquer # O(n^2) nested loops over the input # O(n^3) triple-nested (Floyd-Warshall on small graphs) # O(2^n) subsets, brute-force backtracking # O(n!) permutations # Rough rule on a modern CPU (1s budget): # O(n^2) feasible up to ~10^4 # O(n log n) feasible up to ~10^7 # O(n) feasible up to ~10^8 # O(2^n) feasible up to ~25 # ===== 4) Data-structure ops ===== # Array (fixed size): index O(1); search O(n); insert/delete O(n) # Dynamic array (Vec/List): index O(1); push amortised O(1); insert middle O(n) # Linked list: index O(n); insert/delete at known node O(1); search O(n) # Hash map (HashMap/dict): insert/get/delete avg O(1); WORST O(n) on bad hash # Balanced BST (TreeMap): insert/get/delete O(log n); range O(log n + k) # Heap (priority queue): push/pop O(log n); peek O(1) # Trie: ops O(L) where L is the key length # Disjoint set (Union-Find): nearly O(1) amortised (inverse Ackermann) # Skip list: like balanced BST in practice # Bloom filter: insert/contains O(k) where k is hash count # ===== 5) Algorithms cheat ===== # Sorting (Timsort, IntroSort): O(n log n) worst case # Binary search: O(log n) # Linear search: O(n) # Mergesort, heapsort: O(n log n) deterministic # Quicksort: O(n log n) expected; O(n^2) worst (pathological) # Quickselect: O(n) expected; O(n^2) worst # Dijkstra: O((V + E) log V) with a heap # BFS / DFS: O(V + E) # Floyd-Warshall: O(V^3) # Union-Find Kruskal MST: O(E log E) # Knapsack DP: O(nW) — pseudo-polynomial # Edit distance DP: O(n * m) # Knuth-Morris-Pratt: O(n + m) # Rabin-Karp: expected O(n + m), worst O(nm) # ===== 6) Space matters too ===== # Many 'fast' algorithms use lots of memory. Note when space is the bottleneck. # In-place sort: O(1) extra (heapsort, in-place quicksort) # Mergesort: O(n) extra # Tabulation DP: O(state-space) — sometimes the killer # ===== 7) Worst vs average vs amortised ===== # - Worst: the upper bound on a single call # - Average: expected over inputs (hash-map insert) # - Amortised: per-call cost averaged over a SEQUENCE # (dynamic array push: occasional O(n) resize, amortised O(1)) # ===== 8) When does Big-O lie? ===== # - Constants matter on real hardware (cache locality) # - Small N: O(n^2) bubble sort can beat O(n log n) mergesort for n < 16 # - Hidden allocations: O(n) with malloc per element is slower than O(n) on a preallocated buffer # - Concurrent code: contention can dominate the asymptotic class # Profile to confirm Big-O predictions on your real inputs. # ===== 9) Recipes for spotting the class ===== # - 'For each pair' -> O(n^2) # - 'Halve the search space' -> O(log n) # - 'Sort then sweep' -> O(n log n) # - 'Hash table by key' -> O(n) amortised # - 'For each subset' -> O(2^n) # - 'For each permutation' -> O(n!) # ===== 10) Self-test ===== # Match each to its complexity: # - Two-pointer linear scan over sorted input -> O(n) # - Binary heap top-K -> O(n log k) # - Bellman-Ford shortest path -> O(VE) # - 0/1 knapsack -> O(nW) # - Brute-force subset sum -> O(2^n) # - Trie autocomplete with prefix p over D dict words -> O(p) lookup
Why it matters
Sketch the complexity BEFORE writing the code, then compare to the worst-case input size. Most production "why is this slow?" bugs are O(n^2) hidden inside an O(n) wrapper — spotting them at design time costs minutes; spotting them after a customer complaint costs days.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
// Standard collection costs (typical): // Array push / pop O(1) amortised // HashMap get / set O(1) amortised // TreeMap get / set O(log n) // Sorted array search O(log n) // Heap push / pop O(log n) // String concat in loop O(n^2) — use a list + join insteadTry it Yourself »
Discussion
Loading…