Grinding 500 LeetCode problems is the slow way. The fast way is to recognize that the vast majority of "interesting" coding interview problems are re-skins of about 15 underlying patterns. Master the patterns, and you'll walk into interviews recognizing the shape of each problem in the first 60 seconds — which is what your interviewer is actually scoring.
This guide gives you each pattern's: signal-words to recognize it, a clean template you can write from memory, complexity analysis, and the LeetCode problems that best exemplify it. When you can do one representative problem from each pattern cleanly, you're interview-ready. (Already past coding rounds and prepping for the next stage? See our 14-concept system design cheat sheet and how to pass the Amazon behavioral interview.)
How to Use This Guide
- Skim all 15 patterns once, in order.
- For each pattern, solve the 2 "canonical" problems listed — without looking at the template until you've tried on your own for 25 minutes.
- Then read the template, re-solve cleanly.
- Solve 1–2 more problems from the "practice" list per pattern. That's your minimum — more is fine, less is risky.
- Spaced review: re-do one problem from each pattern every 5–7 days.
Total volume: ~45–60 problems. Versus 500. That's the leverage.
1. Two Pointers
Signal words: "sorted array," "find a pair," "palindrome," "remove duplicates in place."
Core idea: two indices moving toward/with each other, eliminating the need for nested loops.
def two_pointers(arr, target):
left, right = 0, len(arr) - 1
while left < right:
s = arr[left] + arr[right]
if s == target: return [left, right]
if s < target: left += 1
else: right -= 1
return []
Canonical: Two Sum II (LC 167), Valid Palindrome (LC 125). Practice: 3Sum (LC 15), Container With Most Water (LC 11), Trapping Rain Water (LC 42).
2. Sliding Window
Signal words: "substring / subarray with," "maximum / minimum of size K," "longest / shortest window."
def sliding_window(s, k):
left = 0
result = 0
state = {} # or counter, sum, etc.
for right in range(len(s)):
# expand window
state[s[right]] = state.get(s[right], 0) + 1
# shrink while invalid
while window_invalid(state):
state[s[left]] -= 1
if state[s[left]] == 0: del state[s[left]]
left += 1
result = max(result, right - left + 1)
return result
Canonical: Longest Substring Without Repeating Characters (LC 3), Minimum Size Subarray Sum (LC 209). Practice: Longest Repeating Character Replacement (LC 424), Minimum Window Substring (LC 76), Permutation in String (LC 567).
3. Fast & Slow Pointers (Floyd's Cycle Detection)
Signal words: "linked list cycle," "find middle," "happy number," "duplicate number (Floyd's)."
def has_cycle(head):
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow is fast: return True
return False
Canonical: Linked List Cycle (LC 141), Middle of the Linked List (LC 876). Practice: Linked List Cycle II (LC 142), Find the Duplicate Number (LC 287), Happy Number (LC 202).
4. Merge Intervals
Signal words: "intervals," "meeting rooms," "overlap," "insert into," "busy schedule."
def merge(intervals):
intervals.sort(key=lambda x: x[0])
out = [intervals[0]]
for start, end in intervals[1:]:
if start <= out[-1][1]:
out[-1][1] = max(out[-1][1], end)
else:
out.append([start, end])
return out
Canonical: Merge Intervals (LC 56), Insert Interval (LC 57). Practice: Meeting Rooms II (LC 253), Non-overlapping Intervals (LC 435).
5. Cyclic Sort
Signal words: "array of integers 1 to N," "find missing / duplicate numbers," "no extra space."
def cyclic_sort(nums):
i = 0
while i < len(nums):
correct = nums[i] - 1
if nums[i] != nums[correct]:
nums[i], nums[correct] = nums[correct], nums[i]
else:
i += 1
return nums
Canonical: Missing Number (LC 268), Find All Numbers Disappeared in an Array (LC 448). Practice: First Missing Positive (LC 41), Find the Duplicate Number (LC 287).
6. Reversal of a Linked List (In-place)
Signal words: "reverse linked list," "reverse sublist," "rotate linked list."
def reverse(head):
prev = None
curr = head
while curr:
nxt = curr.next
curr.next = prev
prev = curr
curr = nxt
return prev
Canonical: Reverse Linked List (LC 206), Reverse Linked List II (LC 92). Practice: Reverse Nodes in k-Group (LC 25), Rotate List (LC 61).
7. BFS (Tree / Graph Level-Order)
Signal words: "level-order," "shortest path in unweighted graph," "minimum steps to reach," "word ladder."
from collections import deque
def bfs(root):
if not root: return []
q = deque([root])
result = []
while q:
level = []
for _ in range(len(q)):
node = q.popleft()
level.append(node.val)
if node.left: q.append(node.left)
if node.right: q.append(node.right)
result.append(level)
return result
Canonical: Binary Tree Level Order Traversal (LC 102), Word Ladder (LC 127). Practice: Rotting Oranges (LC 994), 01 Matrix (LC 542), Shortest Path in Binary Matrix (LC 1091).
8. DFS (Tree / Graph Recursion + Backtracking)
Signal words: "all paths," "does a path exist," "subsets," "permutations," "combinations," "generate all."
def dfs(node, path, result):
if not node: return
path.append(node.val)
if is_leaf(node):
result.append(list(path))
dfs(node.left, path, result)
dfs(node.right, path, result)
path.pop() # backtrack
Canonical: Path Sum II (LC 113), Subsets (LC 78), Permutations (LC 46). Practice: Combination Sum (LC 39), Word Search (LC 79), N-Queens (LC 51).
9. Two Heaps
Signal words: "median of a stream," "find the middle of," "schedule tasks by priority."
import heapq
class MedianFinder:
def __init__(self):
self.low = [] # max-heap (negate)
self.high = [] # min-heap
def add(self, n):
heapq.heappush(self.low, -n)
heapq.heappush(self.high, -heapq.heappop(self.low))
if len(self.high) > len(self.low):
heapq.heappush(self.low, -heapq.heappop(self.high))
def median(self):
if len(self.low) > len(self.high): return -self.low[0]
return (-self.low[0] + self.high[0]) / 2
Canonical: Find Median from Data Stream (LC 295). Practice: Sliding Window Median (LC 480), IPO (LC 502).
10. Subsets / Combinations (Backtracking)
Signal words: "all subsets," "all combinations," "generate strings of N," "powerset."
def subsets(nums):
result = []
def backtrack(start, path):
result.append(list(path))
for i in range(start, len(nums)):
path.append(nums[i])
backtrack(i + 1, path)
path.pop()
backtrack(0, [])
return result
Canonical: Subsets (LC 78), Permutations (LC 46). Practice: Letter Combinations of a Phone Number (LC 17), Palindrome Partitioning (LC 131), Generate Parentheses (LC 22).
11. Modified Binary Search
Signal words: "sorted array," "rotated," "find first / last occurrence," "capacity / threshold to make X work."
def binary_search(arr, target):
lo, hi = 0, len(arr) - 1
while lo <= hi:
mid = (lo + hi) // 2
if arr[mid] == target: return mid
if arr[mid] < target: lo = mid + 1
else: hi = mid - 1
return -1
Canonical: Binary Search (LC 704), Search in Rotated Sorted Array (LC 33). Practice: Find First and Last Position (LC 34), Koko Eating Bananas (LC 875), Median of Two Sorted Arrays (LC 4).
12. Top-K Elements (Heap)
Signal words: "top K," "kth largest / smallest," "most frequent," "closest points."
import heapq
def top_k(nums, k):
return heapq.nlargest(k, nums)
# or manually, for O(n log k) with a min-heap:
def top_k_manual(nums, k):
h = []
for n in nums:
heapq.heappush(h, n)
if len(h) > k:
heapq.heappop(h)
return h
Canonical: Kth Largest Element (LC 215), Top K Frequent Elements (LC 347). Practice: K Closest Points to Origin (LC 973), Find K Closest Elements (LC 658), Merge k Sorted Lists (LC 23).
13. Topological Sort
Signal words: "course schedule," "dependency order," "build order," "task scheduling with prerequisites."
from collections import deque, defaultdict
def topo_sort(n, edges):
graph = defaultdict(list)
in_deg = [0] * n
for u, v in edges:
graph[u].append(v)
in_deg[v] += 1
q = deque(i for i in range(n) if in_deg[i] == 0)
order = []
while q:
node = q.popleft()
order.append(node)
for nxt in graph[node]:
in_deg[nxt] -= 1
if in_deg[nxt] == 0: q.append(nxt)
return order if len(order) == n else []
Canonical: Course Schedule (LC 207), Course Schedule II (LC 210). Practice: Alien Dictionary (LC 269), Minimum Height Trees (LC 310).
14. Dynamic Programming
Signal words: "maximum / minimum," "count the ways," "can you reach," "longest / shortest," "substructure."
This is really ~5 sub-patterns (1D DP, 2D DP, interval DP, DP on trees, bitmask DP) but the top-down template applies to most:
from functools import cache
def dp_problem(args):
@cache
def solve(state):
if base_case(state): return base_value
return combine(solve(next_state1), solve(next_state2))
return solve(initial_state)
Canonical: Climbing Stairs (LC 70), House Robber (LC 198), Longest Common Subsequence (LC 1143). Practice: Coin Change (LC 322), Longest Increasing Subsequence (LC 300), Edit Distance (LC 72), Word Break (LC 139), Partition Equal Subset Sum (LC 416).
15. Union-Find (Disjoint Set)
Signal words: "connected components," "is there a path between X and Y," "redundant connection," "accounts merge."
class UnionFind:
def __init__(self, n):
self.parent = list(range(n))
self.rank = [0] * 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):
ra, rb = self.find(a), self.find(b)
if ra == rb: return False
if self.rank[ra] < self.rank[rb]: ra, rb = rb, ra
self.parent[rb] = ra
if self.rank[ra] == self.rank[rb]: self.rank[ra] += 1
return True
Canonical: Number of Islands (LC 200) — DFS solution works too, but UF is cleaner. Redundant Connection (LC 684). Practice: Accounts Merge (LC 721), Number of Connected Components (LC 323), Most Stones Removed (LC 947).
The 90/10 Rule
The above 15 patterns will carry you through roughly 90% of mid-level coding interviews. The remaining 10% covers:
- Greedy algorithms (often dressed up as DP — solve DP first, simplify later)
- Bit manipulation (rare; know XOR tricks and single-bit manipulation)
- Trie (for autocomplete, word search — 1–2 problems total)
- Segment trees / Fenwick trees (almost never asked outside of competitive programming interviews)
- Monotonic stack (uncommon but elegant — "next greater element" family)
Pattern-Recognition Workflow During the Interview
This is the mental checklist that takes you from "I don't know this problem" to "I know the pattern" in 60 seconds:
- Input type? Sorted array → binary search / two pointers. Linked list → fast/slow pointers. Graph → BFS/DFS/UF/Topo. Intervals → merge intervals.
- Output type? "All possible…" → backtracking. "Top K" → heap. "Count the ways" → DP. "Shortest path" → BFS (unweighted) or Dijkstra (weighted).
- Constraint hint. N ≤ 20 → backtracking / bitmask DP. N ≤ 100 → O(n³) DP. N ≤ 10⁴ → O(n²). N ≤ 10⁶ → O(n log n) or O(n). N ≤ 10¹⁸ → O(log n).
- Sub-problem repetition? Overlapping sub-problems → DP. Unique sub-problems → divide & conquer or backtracking.
Practice these patterns with AI feedback
CoPilot Interview's coding mode lets you paste a problem (or screenshot it from LeetCode), get a pattern-aware explanation with a clean template, full Big-O analysis, and follow-up questions — so you internalize the pattern, not just memorize the answer.
Try Coding Mode Free →FAQ
How long does it take to master these 15 patterns?
If you can code fluently, ~60–100 hours (6–8 weeks at 10 hr/week). If you're rusty, double that. Don't try to cram in 2 weeks — spaced repetition is what makes the patterns stick.
Should I memorize these templates?
Not word-for-word, but you should be able to write a working template for any pattern from scratch in < 3 minutes. The act of re-deriving the template each time is what cements the pattern.
What about the problems Meta, Google, and Amazon tag as their "top 50"?
Do them after the patterns. Most are either multiple patterns combined or a twist on a canonical problem. Working through a company's top-50 without pattern knowledge = memorization. Working through it with pattern knowledge = pattern recognition practice.
Do I need to know data structures like B-trees, red-black trees?
No. For coding rounds, assume built-in ordered structures (Python's SortedList, Java's TreeMap). You'll never implement a red-black tree in a 45-minute interview.
What's the fastest way from zero to interview-ready?
Minimum viable path: Two Pointers → Sliding Window → DFS/BFS → Binary Search → Heap → DP. These six cover ~70% of interview questions. Hit these first, expand from there.