python - leetcode
This is the easiest gatekeeping round in existence. And it is a blessing for people like me.
Understand that leetcode is all about pattern recognition.
After reading a problem, I should immediately know what pattern it requires.
Easy problems don't really have any pattern required. Medium problems require using 1 pattern. Hard problems require using 2 or more patterns.
Solving medium problems is enough to crack most big tech interviews.
How to get good at this
Learning new patterns
Solve lists only (interview 150, blind 75 etc).
Pick the next problem from the list. Try solving it. If you cannot solve the problem in 45 mins, give up and look at the solution. If the solution has a new patterns that I didn't know, then the entire day is dedicated to that pattern only. Find more problems that have this same pattern and solve them until I know the pattern.
- Pick next problem from the list
- Try solving the problem. If cannot solve it in 45mins, give up and look at the solution.
- If the problem has a new pattern, then the entire day is dedicated to that pattern only.
- GOTO (1)
Know and set my limits:
- I can learn only one new pattern in a day
Remembering studied patterns
I can revise ALL previously known patterns in under an hour.
For remembering, make a note of all patterns I know - pattern name, what problems look like, sample code. This note will be revised daily. Revision typically takes 20 minutes once I am used to it.
Patterns list
Two Pointers
Core idea - maintain 2 indices that move through the data, usually from opposite ends or in the same direction.
Opposite direction:
def two_sum_sorted(nums, target):
left = 0
right = len(nums) - 1
while left < right:
total = nums[left] + nums[right]
if total == target:
return [left, right]
elif total < target:
left += 1
else:
right -= 1
return [-1, -1]
Same direction (slow/fast pointer):
def remove_duplicates(nums):
if not nums:
return 0
slow = 0
for fast in range(1, len(nums)):
if nums[fast] != nums[slow]:
slow += 1
nums[slow] = nums[fast]
return slow + 1
Identify
- Input array is sorted
- Look for a pair of elements satisfying some relationships
- Need to compare elements from both ends
- Need to modify/filter array in-place (typically slow+fast pointers)
Problems - 2 pointers
- 167 - Two Sum II - Input Array Is Sorted, https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/ (Two Pointers)
- 26 - Remove Duplicates from Sorted Array, https://leetcode.com/problems/remove-duplicates-from-sorted-array/ (Two Pointers / In-place Array)
- 344 - Reverse String, https://leetcode.com/problems/reverse-string/ (Two Pointers)
- 125 - Valid Palindrome, https://leetcode.com/problems/valid-palindrome/ (Two Pointers)
- 15 - 3Sum, https://leetcode.com/problems/3sum/ (Sorting + Two Pointers)
- 11 - Container With Most Water, https://leetcode.com/problems/container-with-most-water/ (Two Pointers)
- 88 - Merge Sorted Array, https://leetcode.com/problems/merge-sorted-array/ (Two Pointers)
- 283 - Move Zeroes, https://leetcode.com/problems/move-zeroes/ (Two Pointers)
Problems - Fast & Slow Pointers
- 141 - Linked List Cycle, https://leetcode.com/problems/linked-list-cycle/ (Floyd's Cycle Detection)
- 142 - Linked List Cycle II, https://leetcode.com/problems/linked-list-cycle-ii/ (Floyd's Cycle Detection)
- 876 - Middle of the Linked List, https://leetcode.com/problems/middle-of-the-linked-list/ (Fast & Slow Pointers)
- 202 - Happy Number, https://leetcode.com/problems/happy-number/ (Cycle Detection)
- 287 - Find the Duplicate Number, https://leetcode.com/problems/find-the-duplicate-number/ (Floyd's Cycle Detection)
- 234 - Palindrome Linked List, https://leetcode.com/problems/palindrome-linked-list/ (Fast/Slow Pointer + Reverse List)
- 143 - Reorder List, https://leetcode.com/problems/reorder-list/ (Fast/Slow Pointer + Reverse + Merge)
DFS
Uses stack or recursion
# ITERATIVE
def dfs(node):
if node is None:
return
# process node
for neighbor in node.neighbors:
dfs(neighbor)
# RECURSIVE
def dfs(graph, start):
stack = [start]
visited = set()
while stack:
node = stack.pop()
if node in visited:
continue
visited.add(node)
for neighbor in graph[node]:
stack.append(neighbor)
DFS - grid
def dfs(row, col):
if out_of_bounds(row, col):
return
if visited[row][col]:
return
visited[row][col] = True
dfs(row + 1, col)
dfs(row - 1, col)
dfs(row, col + 1)
dfs(row, col - 1)
Identification
- Explore all paths (dfs + backtracking)
- Generate combinations, permutations, subsets
- Word search
- Trees where need to explore subtrees
- Eg - Find max depth of a binary tree
def maxDepth(root):
if not root:
return 0
return 1 + max(
maxDepth(root.left),
maxDepth(root.right)
)
Connected components
- How many islands are there
- Mark all cells connected to this cell
def dfs(grid, r, c):
if (
r < 0 or r >= len(grid) or
c < 0 or c >= len(grid[0]) or
grid[r][c] != "1"
):
return
grid[r][c] = "0"
dfs(grid, r + 1, c)
dfs(grid, r - 1, c)
dfs(grid, r, c + 1)
dfs(grid, r, c - 1)
Problems
- 200 - Number of Islands, https://leetcode.com/problems/number-of-islands/ (DFS / BFS on Grid)
- 733 - Flood Fill, https://leetcode.com/problems/flood-fill/ (DFS / BFS on Grid)
- 133 - Clone Graph, https://leetcode.com/problems/clone-graph/ (DFS / BFS + HashMap)
- 104 - Maximum Depth of Binary Tree, https://leetcode.com/problems/maximum-depth-of-binary-tree/ (Tree DFS)
- 257 - Binary Tree Paths, https://leetcode.com/problems/binary-tree-paths/ (Tree DFS + Backtracking)
- 261 - Graph Valid Tree, https://leetcode.com/problems/graph-valid-tree/ (DFS / BFS / Union Find)
- 112 - Path Sum, https://leetcode.com/problems/path-sum/ (Tree DFS)
- 721 - Accounts Merge, https://leetcode.com/problems/accounts-merge/ (DFS / Union Find)
- 417 - Pacific Atlantic Water Flow, https://leetcode.com/problems/pacific-atlantic-water-flow/ (Matrix DFS / BFS)
BFS
Uses a queue
from collections import deque
def bfs(graph, start):
queue = deque([start])
visited = {start}
while queue:
node = queue.popleft()
# process node
for neighbor in graph[node]:
if neighbor not in visited:
visited.add(neighbor)
queue.append(neighbor)
Identification
- Reach a node using minimum number of edges
- Minimum moves from A to B
- Shortest path in an unweighted graph
- Shortest path, nearest cell, fewest moves, distance from source
- Level order transversal
- Return nodes level by level
from collections import deque
def level_order(root):
if not root:
return []
queue = deque([root])
result = []
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
Prefix Sum
- Precompute cumulative sums so that a range sum can be calculated in O(1).
- Convert a contiguous subarray problem into a difference between two prefix states.
Prefix sum + hashmap is a common combination
BASIC
def prefix_sum(nums):
prefix = [0] * (len(nums) + 1)
for i in range(len(nums)):
prefix[i + 1] = prefix[i] + nums[i]
return prefix
nums = [2, 4, 1, 5, 3]
prefix = prefix_sum(nums)
# Sum of nums[1:4] → 4 + 1 + 5
left = 1
right = 3
result = prefix[right + 1] - prefix[left]
print(result) # 10
WITH HASHMAP
`count += seen[prefix - k]`
from collections import defaultdict
def subarray_sum(nums, k):
prefix = 0
count = 0
seen = defaultdict(int)
seen[0] = 1
for num in nums:
prefix += num
# Have we seen a prefix that makes the
# current subarray sum equal to k?
count += seen[prefix - k]
seen[prefix] += 1
return count
nums = [1, 2, 3, -2, 2]
k = 3
print(subarray_sum(nums, k))
Identification
Look for problems involving repeated sums over contiguous ranges.
- Contiguous subarray and Sum/property of subarray?
- Think Prefix Sum
- Also need to count/find matching subarrays?
- Prefix Sum + HashMap
| Problem clue | Think |
|---|---|
| Range sum queries | Prefix Sum |
Sum of l..r|Prefix Sum |
|
| Repeated contiguous sums | Prefix Sum |
| Subarray sum = K | Prefix Sum + HashMap |
| Count subarrays with condition | Prefix Sum + HashMap |
| Equal 0s and 1s | Prefix Sum |
| Balance between two values | Prefix Sum |
| 2D rectangular sum | 2D Prefix Sum |
| Positive numbers + target window | Often Sliding Window |
Most important - Subarray Sum = K
Eg - Number of subarrays whose sum equals 3
from collections import defaultdict
def subarray_sum(nums, k):
count = 0
prefix = 0
frequencies = defaultdict(int)
frequencies[0] = 1
for num in nums:
prefix += num
count += frequencies[prefix - k]
frequencies[prefix] += 1
return count
Words like:
- subarray
- range sum
- sum between
iandj - contiguous
- cumulative
- running sum
- sum equals
k - number of subarrays
- balance
- frequency/count within a range
Problems
- 560 - Subarray Sum Equals K, https://leetcode.com/problems/subarray-sum-equals-k/ (Prefix Sum + HashMap)
- 974 - Subarray Sums Divisible by K, https://leetcode.com/problems/subarray-sums-divisible-by-k/ (Prefix Sum + Modulo HashMap)
- 930 - Binary Subarrays With Sum, https://leetcode.com/problems/binary-subarrays-with-sum/ (Prefix Sum / Sliding Window)
- 1248 - Count Number of Nice Subarrays, https://leetcode.com/problems/count-number-of-nice-subarrays/ (Prefix Sum + Counting)
- 1074 - Number of Submatrices That Sum to Target, https://leetcode.com/problems/number-of-submatrices-that-sum-to-target/ (2D Prefix Sum)
- 363 - Max Sum of Rectangle No Larger Than K, https://leetcode.com/problems/max-sum-of-rectangle-no-larger-than-k/ (2D Prefix Sum + Binary Search)
- 437 - Path Sum III, https://leetcode.com/problems/path-sum-iii/ (Tree DFS + Prefix Sum)
- 325 - Maximum Size Subarray Sum Equals k, https://leetcode.com/problems/maximum-size-subarray-sum-equals-k/ (Prefix Sum + HashMap)
Heap / Priority Queue
Problems
- 1046 - Last Stone Weight, https://leetcode.com/problems/last-stone-weight/ (Heap / Priority Queue)
- 347 - Top K Frequent Elements, https://leetcode.com/problems/top-k-frequent-elements/ (Heap / Bucket Sort)
- 215 - Kth Largest Element in an Array, https://leetcode.com/problems/kth-largest-element-in-an-array/ (Heap / Quickselect)
- 23 - Merge K Sorted Lists, https://leetcode.com/problems/merge-k-sorted-lists/ (Min Heap)
- 621 - Task Scheduler, https://leetcode.com/problems/task-scheduler/ (Heap / Greedy)
- 253 - Meeting Rooms II, https://leetcode.com/problems/meeting-rooms-ii/ (Min Heap / Intervals)
Dynamic Programming
Problems
- 70 - Climbing Stairs, https://leetcode.com/problems/climbing-stairs/ (1D DP)
- 198 - House Robber, https://leetcode.com/problems/house-robber/ (1D DP)
- 5 - Longest Palindromic Substring, https://leetcode.com/problems/longest-palindromic-substring/ (String DP)
- 1143 - Longest Common Subsequence, https://leetcode.com/problems/longest-common-subsequence/ (2D DP)
- 62 - Unique Paths, https://leetcode.com/problems/unique-paths/ (Grid DP)
- 322 - Coin Change, https://leetcode.com/problems/coin-change/ (Unbounded Knapsack DP)
Binary Search
Problems
- 33 - Search in Rotated Sorted Array, https://leetcode.com/problems/search-in-rotated-sorted-array/ (Modified Binary Search)
- 153 - Find Minimum in Rotated Sorted Array, https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/ (Modified Binary Search)
- 34 - Find First and Last Position of Element in Sorted Array, https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/ (Binary Search Boundaries)
- 875 - Koko Eating Bananas, https://leetcode.com/problems/koko-eating-bananas/ (Binary Search on Answer)
- 1011 - Capacity To Ship Packages Within D Days, https://leetcode.com/problems/capacity-to-ship-packages-within-d-days/ (Binary Search on Answer)
- 1482 - Minimum Number of Days to Make m Bouquets, https://leetcode.com/problems/minimum-number-of-days-to-make-m-bouquets/ (Binary Search on Answer)
- 74 - Search a 2D Matrix, https://leetcode.com/problems/search-a-2d-matrix/ (Binary Search)
Misc
DFS vs BFS
- DFS - find all possibilities, explore all possibilities
- BFS - find optimal (shortest path)
| Signal | DFS | BFS |
|---|---|---|
| Explore deeply | ✅ | |
| Explore level-by-level | ✅ | |
| Shortest path, unweighted | ✅ | |
| Connected components | ✅ | ✅ |
| Number of islands | ✅ | ✅ |
| Tree traversal | ✅ | ✅ |
| Generate permutations | ✅ | |
| Generate subsets | ✅ | |
| Backtracking | ✅ | |
| Minimum moves | ✅ | |
| Nearest/closest node | ✅ | |
| Level order | ✅ | |
| Path existence | ✅ | ✅ |
These are symptoms of BFS/DFS:
Tree
Graph
Grid
Island
Connected
Path
Reachable
Neighbors
Then choose an algo:
All possibilities? → DFS / Backtracking
Connected component? → DFS or BFS
Shortest path? → BFS
Minimum moves? → BFS
Level by level? → BFS
Deep subtree computation → DFS