Skip to content

Common Patterns Quick Reference (1 page)

Problem Type -> Algorithm Mapping

Problem Signal Pattern / Algorithm
"Find shortest path" (unweighted) BFS
"Find shortest path" (weighted, non-neg) Dijkstra
"Find shortest path" (negative weights) Bellman-Ford
"All pairs shortest path" Floyd-Warshall
"Connected components" DFS/BFS or Union-Find
"Detect cycle" (directed) DFS with coloring (white/gray/black)
"Detect cycle" (undirected) Union-Find or DFS with parent tracking
"Ordering with dependencies" Topological Sort
"Minimum spanning tree" Kruskal's (sparse) or Prim's (dense)
"Find in sorted array" Binary Search
"Minimum/maximum X that satisfies Y" Binary Search on Answer
"Kth smallest/largest" Heap (O(n log k)) or Quick Select (O(n) avg)
"Top K elements" Heap of size k
"Median of stream" Two heaps (max-heap + min-heap)
"Merge K sorted" Min-heap of size k
"Subarray with sum/property" Prefix sum + hash map
"Contiguous subarray optimization" Sliding window or Kadane's
"Substring matching/anagrams" Sliding window + counter
"Longest substring with condition" Sliding window (variable)
"All subsets/combinations" Backtracking or bitmask DP
"All permutations" Backtracking
"Constraint satisfaction" Backtracking with pruning
"Count ways" / "min cost" Dynamic Programming
"String comparison/edit" 2D DP (LCS, edit distance)
"Longest increasing subsequence" DP + binary search O(n log n)
"Interval scheduling" Sort + greedy or sweep line
"Overlapping intervals" Sort by start, merge
"Maximum in sliding window" Monotonic deque
"Next greater/smaller element" Monotonic stack
"Histogram largest rectangle" Monotonic stack
"Word search / prefix matching" Trie
"Autocomplete" Trie + DFS
"Disjoint groups / merging" Union-Find

Red Flags & Hints in Problem Descriptions

Keyword / Hint Think...
"sorted array" Binary search, two pointers
"O(log n)" required Binary search
"minimum number of steps" BFS (unweighted shortest path)
"contiguous subarray" Sliding window, prefix sum, Kadane's
"at most K distinct" Sliding window with counter
"palindrome" Two pointers (expand from center), DP
"parentheses / brackets" Stack
"evaluate expression" Stack (two stacks: operators + operands)
"matrix traversal" BFS/DFS on grid
"island counting" BFS/DFS or Union-Find on grid
"tree diameter/depth" DFS (post-order)
"serialize / level-order" BFS
"lowest common ancestor" DFS with recursion
"number of ways" DP (usually)
"can you partition into..." DP (subset sum variant)
"maximum profit" DP or greedy
"buy and sell stock" State machine DP or Kadane's
"robber / no adjacent" DP: dp[i] = max(dp[i-1], dp[i-2]+val)
"word break / segmentation" DP + hash set, or Trie
"design" / "implement" Choose right data structure, think API
"stream" / "online" Heap, balanced BST, or amortized structure
"frequency" / "mode" Counter / hash map
"graph" not explicitly stated Build graph from relationships, then BFS/DFS

Decision Framework: When Stuck

1. What is the INPUT SIZE?
   -> Determines max acceptable time complexity (see Big-O sheet)

2. What is the OUTPUT?
   -> Boolean: search/decision -> binary search, DFS, DP
   -> Single value: optimization -> DP, greedy, binary search on answer
   -> All solutions: enumeration -> backtracking
   -> Ordering: topological sort, sort + greedy

3. Can I SORT the input?
   -> Often unlocks two pointers, binary search, greedy

4. Can I use a HASH MAP?
   -> Trade space for time: O(n) lookup instead of O(n) scan

5. Is there OPTIMAL SUBSTRUCTURE + OVERLAPPING SUBPROBLEMS?
   -> Yes: Dynamic Programming
   -> Optimal substructure only: Greedy (prove greedy choice works)

6. Does the problem have a GRAPH structure?
   -> Explicit or implicit graph -> BFS/DFS/Dijkstra

7. Am I choosing from INTERVALS or EVENTS?
   -> Sort by end time (scheduling), sort by start (merging), sweep line

Gotchas & Common Mistakes

Mistake Fix
list.pop(0) in a loop Use collections.deque.popleft() -> O(1)
s += char in a loop Use parts.append(char), then ''.join(parts)
Mutable default arg def f(a=[]) Use def f(a=None): a = a or []
Modifying list while iterating Iterate over a copy or use indices
Integer overflow Python has arbitrary precision ints (no overflow)
Float precision Use math.isclose() or integer math when possible
Off-by-one in binary search Check: lo <= hi vs lo < hi, hi = n vs hi = n-1
Forgetting to copy in backtracking result.append(path[:]) not result.append(path)
@lru_cache with mutable args Convert lists to tuples first
DFS hitting recursion limit sys.setrecursionlimit(10**6) or use iterative
Dijkstra with negative weights Use Bellman-Ford instead
BFS without marking visited early Mark when ENQUEUING, not when dequeuing
Graph: forgetting self-loops/multi-edges Check problem constraints
Sorting stability assumptions Python sort IS stable (Timsort)
// with negative numbers -7 // 2 = -4 in Python (floors toward -inf), use int(-7/2) = -3 for truncation toward zero