The Right Way to Prepare
Doing 300 random LeetCode problems doesn't work. You memorize solutions instead of learning to think. The right approach: learn the ~10 fundamental patterns, then do 3-5 problems per pattern until you recognize the template.
Pattern 1: Two Pointers
Recognize when: sorted array, find pair/triplet with a condition.
def two_sum_sorted(arr, target):
left, right = 0, len(arr) - 1
while left < right:
s = arr[left] + arr[right]
if s == target: return [left, right]
elif s < target: left += 1
else: right -= 1
return []
Practice: Two Sum II, 3Sum, Container With Most Water
Pattern 2: Sliding Window
Recognize when: subarray/substring that satisfies a condition; window shrinks/grows.
def longest_substring_no_repeat(s):
seen = {}
left = best = 0
for right, ch in enumerate(s):
if ch in seen and seen[ch] >= left:
left = seen[ch] + 1
seen[ch] = right
best = max(best, right - left + 1)
return best
Practice: Longest Substring Without Repeating Characters, Minimum Window Substring, Max Sum Subarray of Size K
Pattern 3: Fast & Slow Pointers
Recognize when: linked list cycle detection, finding middle of linked list.
def has_cycle(head):
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return False
Practice: Linked List Cycle, Find Middle of Linked List, Happy Number
Pattern 4: Tree BFS
Recognize when: level-order traversal, shortest path in unweighted graph, "minimum depth."
from collections import deque
def level_order(root):
if not root: return []
result, queue = [], deque([root])
while queue:
level = []
for _ in range(len(queue)):
node = queue.popleft()
level.append(node.val)
if node.left: queue.append(node.left)
if node.right: queue.append(node.right)
result.append(level)
return result
Practice: Level Order Traversal, Minimum Depth of Binary Tree, Rotting Oranges
Pattern 5: Tree DFS
Recognize when: path sum, tree validation, tree structure questions.
def has_path_sum(root, target):
if not root: return False
if not root.left and not root.right:
return root.val == target
return (has_path_sum(root.left, target - root.val) or
has_path_sum(root.right, target - root.val))
Practice: Path Sum, Validate BST, Lowest Common Ancestor, Diameter of Binary Tree
Pattern 6: Binary Search (Beyond Basic)
Recognize when: sorted array, "find minimum/maximum that satisfies condition."
The key insight: binary search on the answer space, not just the array index.
def min_speed_to_arrive(dist, hour):
def can_make_it(speed):
time = sum(ceil(d / speed) for d in dist[:-1]) + dist[-1] / speed
return time <= hour
left, right = 1, 10**7
while left < right:
mid = (left + right) // 2
if can_make_it(mid):
right = mid
else:
left = mid + 1
return left if can_make_it(left) else -1
Practice: Search in Rotated Array, Find Minimum in Rotated Array, Koko Eating Bananas
Pattern 7: Dynamic Programming
Recognize when: "count ways," "minimum/maximum," overlapping subproblems.
Template: define dp[i] as the answer for subproblem i.
def climb_stairs(n):
if n <= 2: return n
dp = [0] * (n + 1)
dp[1], dp[2] = 1, 2
for i in range(3, n + 1):
dp[i] = dp[i-1] + dp[i-2]
return dp[n]
Practice: Climbing Stairs, Coin Change, Longest Common Subsequence, 0/1 Knapsack
Pattern 8: Heap / Priority Queue
Recognize when: "top K," "kth largest/smallest," merge K sorted things.
import heapq
def find_k_largest(nums, k):
# Min heap of size k โ efficiently maintains top K
heap = nums[:k]
heapq.heapify(heap) # O(k)
for n in nums[k:]:
if n > heap[0]:
heapq.heapreplace(heap, n) # O(log k)
return heap[0] # kth largest
Practice: Kth Largest Element, Top K Frequent Elements, Merge K Sorted Lists
Pattern 9: Backtracking
Recognize when: "all combinations/permutations/subsets," exploring decision trees.
def subsets(nums):
result = []
def backtrack(start, current):
result.append(current[:])
for i in range(start, len(nums)):
current.append(nums[i])
backtrack(i + 1, current)
current.pop() # undo choice
backtrack(0, [])
return result
Practice: Subsets, Permutations, Combination Sum, N-Queens
Pattern 10: Graph Traversal
Recognize when: connectivity, shortest path (BFS), cycles, islands.
def num_islands(grid):
if not grid: return 0
count = 0
def dfs(r, c):
if r < 0 or c < 0 or r >= len(grid) or c >= len(grid[0]) or grid[r][c] != '1':
return
grid[r][c] = '0' # mark visited
for dr, dc in [(0,1),(0,-1),(1,0),(-1,0)]:
dfs(r+dr, c+dc)
for r in range(len(grid)):
for c in range(len(grid[0])):
if grid[r][c] == '1':
dfs(r, c)
count += 1
return count
Practice: Number of Islands, Clone Graph, Course Schedule (cycle detection), Dijkstra's algorithm
How to Study Efficiently
- Learn the pattern template for each
- Do 3 problems per pattern (easy โ medium โ medium-hard)
- After solving, ask: "Which pattern did this use? Could I recognize it faster?"
- Focus on problems where you got stuck, not ones you found easy
With 10 patterns ร 3 problems = 30 problems, you'll recognize the approach for ~80% of medium-level interview questions.
Key Takeaways
- Learn patterns, not solutions โ recognition is the skill
- The 10 patterns: Two Pointers, Sliding Window, Fast/Slow Pointers, BFS, DFS, Binary Search, DP, Heap, Backtracking, Graph Traversal
- 30 carefully chosen problems (3 per pattern) > 200 random problems
- Always explain your pattern recognition out loud in interviews โ that's what they're evaluating