Study Guide [DS/A]

Python Patterns Cheatsheet

Core Data Structures

# Lists
arr = [1, 2, 3]
arr.append(4)
last = arr.pop()          # removes and returns last
arr[0]                    # first element
arr[-1]                   # last element
arr[1:3]                  # slice: index 1 inclusive to 3 exclusive
arr[::-1]                 # reversed copy
len(arr)

# Sets β€” O(1) average membership
s = {1, 2, 3}
empty_set = set()
s.add(4)
s.discard(2)              # no error if missing; .remove() raises KeyError
if 3 in s: ...
unique_vals = set(arr)

# Dicts
mp = {'a': 1, 'b': 2}
mp['c'] = 3
val = mp.get('d', 0)      # 0 if 'd' not in mp β€” no KeyError
if 'a' in mp: ...
del mp['a']

# Tuples β€” immutable; hashable (can be dict keys or set members)
t = (1, 2, 3)
t[0]
list(t)                   # convert to list
tuple([1, 2, 3])          # convert from list

Iteration Patterns

# Arrays β€” prefer enumerate over range(len(...))
for x in arr: ...
for i in range(len(arr)): ...
for i, x in enumerate(arr): ...      # index + value together
for x in reversed(arr): ...

# range(start, stop, step) β€” stop is exclusive
range(5, 10)                          # 5, 6, 7, 8, 9
range(0, 10, 2)                       # 0, 2, 4, 6, 8
range(10, 0, -1)                      # 10, 9, ..., 1 β€” count down

# Dicts
for k in mp: ...                      # keys
for v in mp.values(): ...
for k, v in mp.items(): ...           # key + value (most common)

# Sets β€” order not guaranteed
for x in s: ...
for x in sorted(s): ...              # if you need a stable order

2D Grids

# Initialize β€” m rows of n columns
rows, cols = 3, 4
grid = [[0] * cols for _ in range(rows)]   # CORRECT β€” independent rows
# bad_grid = [[0] * cols] * rows           # WRONG β€” all rows are the same object

# Iterate by index
for r in range(rows):
    for c in range(cols):
        val = grid[r][c]

# Iterate with enumerate (index + value)
for r, row in enumerate(grid):
    for c, val in enumerate(row):
        print(r, c, val)

# 4-direction deltas (up, down, left, right)
dirs_4 = [(-1, 0), (1, 0), (0, -1), (0, 1)]

# 8-direction deltas (including diagonals)
dirs_8 = [(-1,0),(1,0),(0,-1),(0,1),(-1,-1),(-1,1),(1,-1),(1,1)]

# Bounds check helper
rows, cols = len(grid), len(grid[0])
in_bounds = lambda r, c: 0 <= r < rows and 0 <= c < cols

for dr, dc in dirs_4:
    nr, nc = r + dr, c + dc
    if in_bounds(nr, nc):
        ...   # safe to access grid[nr][nc]

# Helper β€” all valid neighbor indices for (i, j), bounds-checked
def get_neighbors(i, j, rows, cols):
    neighbors = []
    for dr, dc in dirs_4:
        ni, nj = i + dr, j + dc
        if 0 <= ni < rows and 0 <= nj < cols:
            neighbors.append((ni, nj))
    return neighbors

Algorithm Templates

# Two pointers
l, r = 0, len(arr) - 1

# Sliding window
from collections import defaultdict
window = defaultdict(int)
l = 0
for r in range(len(s)):
    window[s[r]] += 1
    while invalid(window):
        window[s[l]] -= 1
        l += 1

# BFS β€” graph
from collections import deque
q = deque([start])
visited = {start}
while q:
    node = q.popleft()
    for nei in graph[node]:
        if nei not in visited:
            visited.add(nei)
            q.append(nei)

# BFS β€” 2D grid
from collections import deque
def bfs_grid(grid, start_r, start_c):
    rows, cols = len(grid), len(grid[0])
    dirs = [(-1,0),(1,0),(0,-1),(0,1)]
    in_bounds = lambda r, c: 0 <= r < rows and 0 <= c < cols
    q = deque([(start_r, start_c)])
    visited = {(start_r, start_c)}
    while q:
        r, c = q.popleft()
        for dr, dc in dirs:
            nr, nc = r + dr, c + dc
            if in_bounds(nr, nc) and (nr, nc) not in visited:
                visited.add((nr, nc))
                q.append((nr, nc))

# DFS β€” iterative
stack = [start]
visited = {start}
while stack:
    node = stack.pop()
    for nei in graph[node]:
        if nei not in visited:
            visited.add(nei)
            stack.append(nei)

# Binary search β€” lo/hi loop
def binary_search(arr, target):
    lo, hi = 0, len(arr) - 1
    while lo <= hi:
        mid = (lo + hi) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            lo = mid + 1
        else:
            hi = mid - 1
    return -1

Common Gotchas

# 1. Mutable default arguments β€” shared across all calls
def f_bad(x, arr=[]):      # BAD
    arr.append(x); return arr
def f_good(x, arr=None):   # GOOD
    if arr is None: arr = []
    arr.append(x); return arr

# 2. is vs == 
a, b = [1, 2], [1, 2]
a == b   # True  β€” same value
a is b   # False β€” different objects; use `is` only for None checks
if x is None: ...

# 3. Integer vs float division
5 / 2    # 2.5  (float)
5 // 2   # 2    (floor); use for index math: mid = (lo + hi) // 2

# 4. sort() vs sorted() β€” sort() mutates and returns None
arr.sort()              # in-place, returns None
new_arr = sorted(arr)   # returns new list
arr = arr.sort()        # BUG β€” arr is now None

# 5. Modifying a list while iterating over it
for x in arr:
    if condition(x): arr.remove(x)        # BAD β€” skips elements
new_arr = [x for x in arr if not condition(x)]  # GOOD

# 6. range() is end-exclusive
range(n)              # 0 .. n-1
range(start, end)     # start .. end-1
for i in range(1, n + 1): ...   # inclusive 1..n

# 7. any() / all()
if any(x > 0 for x in arr): ...   # at least one satisfies
if all(x >= 0 for x in arr): ...  # every element satisfies

# In the wild β€” array-based trie node, "does this child have anything left?"
# no dict-style falsy check available on a fixed-size list, so scan it
if all(c is None for c in child.children): ...   # child is a dead branch, safe to prune
Python Syntax Drills β€” Code Examples & Practice Problems

collections.defaultdict

# Never KeyError β€” missing keys auto-initialize
graph = defaultdict(list)
graph['a'].append('b')        # no need to check if 'a' exists first

freq = defaultdict(int)
for c in "banana":
    freq[c] += 1              # starts at 0 automatically

# Value is your own class β€” pass the class itself, no lambda needed,
# as long as __init__ takes no required args (same idea as list/int above)
class Node:
    def __init__(self):
        self.children = defaultdict(Node)   # char -> Node, self-referential
        self.is_end = False

# Nested defaultdict β€” DOES need a lambda. defaultdict(list) evaluates
# immediately to one instance; that instance isn't callable, so the outer
# defaultdict needs a zero-arg factory that builds a fresh one each time.
groups = defaultdict(lambda: defaultdict(list))
groups['a']['b'].append(1)    # defaultdict(defaultdict(list)) would TypeError here
#ProblemDiff
49Group AnagramsMedium
207Course ScheduleMedium
133Clone GraphMedium
208Implement TrieMedium

collections.Counter

from collections import Counter

c = Counter("banana")         # Counter({'a': 3, 'n': 2, 'b': 1})
c.most_common(2)              # [('a', 3), ('n', 2)]
c['z']                        # 0 β€” no KeyError

# Subtract two counters
c1 = Counter("abc")
c2 = Counter("ab")
c1 - c2                       # Counter({'c': 1})
#ProblemDiff
242Valid AnagramEasy
347Top K Frequent ElementsMedium
76Minimum Window SubstringHard

collections.deque

from collections import deque

dq = deque([1, 2, 3])
dq.appendleft(0)    # O(1) β€” unlike list.insert(0, x)
dq.popleft()        # O(1) β€” unlike list.pop(0)

# BFS template
queue = deque([start])
while queue:
    node = queue.popleft()
    for neighbor in graph[node]:
        queue.append(neighbor)
#ProblemDiff
102Binary Tree Level Order TraversalMedium
127Word LadderHard
239Sliding Window MaximumHard

heapq

import heapq

h = []
heapq.heappush(h, 3)
heapq.heappop(h)          # returns smallest

# Max heap β€” negate values
heapq.heappush(h, -5)
-heapq.heappop(h)         # returns 5

heapq.heapify(nums)       # in-place, O(n)
heapq.nlargest(3, nums)   # [5, 4, 3]
#ProblemDiff
215Kth Largest Element in an ArrayMedium
23Merge K Sorted ListsHard
295Find Median from Data StreamHard
621Task SchedulerMedium

List Comprehensions Β· enumerate Β· zip

# List comprehension
squares = [x**2 for x in range(10) if x % 2 == 0]

# Grid init β€” DO NOT do [[0]*n]*m (aliasing bug!)
grid = [[0] * n for _ in range(m)]

# enumerate β€” index + value together
for i, val in enumerate(nums):
    print(i, val)

# zip β€” pair two lists, or transpose a matrix
for a, b in zip(list1, list2): ...
transposed = list(zip(*matrix))   # [(1,4),(2,5),(3,6)]
#ProblemDiff
48Rotate ImageMedium
54Spiral MatrixMedium
200Number of IslandsMedium

sorted() with key=

# Sort by second element
sorted(pairs, key=lambda x: x[1])

# Multi-key sort
sorted(words, key=lambda w: (len(w), w))

# Descending
sorted(nums, reverse=True)

# In-place
intervals.sort(key=lambda x: x[0])  # sort by start
#ProblemDiff
56Merge IntervalsMedium
435Non-overlapping IntervalsMedium
253Meeting Rooms IIMedium

dict.get(key, default)

d = {"a": 1}
d.get("b", 0)              # 0, no KeyError

# One-liner frequency count
freq = {}
freq[c] = freq.get(c, 0) + 1
#ProblemDiff
1Two SumEasy
560Subarray Sum Equals KMedium
146LRU CacheMedium

String Methods

s = "  hello world  "
s.strip()               # "hello world"
s.split()               # ["hello", "world"]
" ".join(["a","b","c"]) # "a b c"
s[::-1]                 # reverse

"abc".isalpha()         # True
"123".isdigit()         # True
"abc123".isalnum()      # True
#ProblemDiff
125Valid PalindromeEasy
151Reverse Words in a StringMedium
5Longest Palindromic SubstringMedium

set Operations

a = {1, 2, 3}
b = {2, 3, 4}

a | b    # union       {1,2,3,4}
a & b    # intersect   {2,3}
a - b    # difference  {1}

# O(1) lookup β€” prefer over list for membership checks
seen = set()
if x not in seen:
    seen.add(x)
#ProblemDiff
217Contains DuplicateEasy
128Longest Consecutive SequenceMedium
141Linked List CycleEasy

bisect

import bisect

nums = [1, 3, 4, 7, 9]

bisect.bisect_left(nums, 4)    # 2 β€” first index >= 4
bisect.bisect_right(nums, 4)   # 3 β€” first index > 4

bisect.insort(nums, 5)         # insert, keeping sorted β€” O(n)

# Check membership in O(log n)
idx = bisect.bisect_left(nums, x)
found = idx < len(nums) and nums[idx] == x
#ProblemDiff
981Time Based Key-Value StoreMedium
300Longest Increasing SubsequenceMedium
315Count of Smaller Numbers After SelfHard
Quick signal β†’ tool lookup
"top K" / "kth largest"heapq
BFS / shortest pathdeque
frequency / anagramCounter
graph adjacency / groupingdefaultdict(list)
sorted input + O(log n) searchbisect
membership / dedupset
sort by custom rulesorted(key=...)
1

Base Building β€” Weeks 1–2

Python fluency Β· core data structures Β· behavioral foundations
Arrays, HashMaps, Sets
#ProblemDiff
1Two SumEasyGoogle
217Contains DuplicateEasy
242Valid AnagramEasy
121Best Time to Buy and Sell StockEasyGoogle
49Group AnagramsMediumGoogle
238Product of Array Except SelfMediumGoogle
560Subarray Sum Equals KMediumGoogle
Linked Lists, Stacks, Queues
Python Syntax Drills β€” Learn These Cold
Behavioral Bank β€” 5 STAR Stories to Write
Use "I", not "we". Quantify results where possible. Aim for 90-second verbal delivery each.
Phase 1 Exit Checklist
2

Build β€” Weeks 3–5

Medium problems under time pressure Β· system design foundations
Two Pointers Β· Sliding Window Β· Binary Search
Trees Β· Graphs Β· Backtracking
#ProblemDiff
104Maximum Depth of Binary TreeEasy
102Binary Tree Level Order TraversalMediumGoogle
199Binary Tree Right Side ViewMediumGoogle
98Validate Binary Search TreeMediumGoogle
236Lowest Common Ancestor of a Binary TreeMediumGoogle
200Number of IslandsMediumGoogle
133Clone GraphMedium
207Course ScheduleMediumGoogle
417Pacific Atlantic Water FlowMedium
78SubsetsMedium
46PermutationsMediumGoogle
39Combination SumMedium
79Word SearchMediumGoogle
Dynamic Programming Β· Heaps
#ProblemDiff
70Climbing StairsEasy
198House RobberMedium
322Coin ChangeMediumGoogle
91Decode WaysMediumGoogle
139Word BreakMediumGoogle
62Unique PathsMedium
1143Longest Common SubsequenceMedium
215Kth Largest Element in an ArrayMediumGoogle
347Top K Frequent ElementsMedium
621Task SchedulerMediumGoogle
295Find Median from Data StreamHardGoogle
System Design Curriculum
Frontend system design β€” these come up at product-focused companies. Be ready to discuss:
  • How would you design a component library from scratch?
  • Client-side routing vs SSR β€” when to use which?
  • How do you handle state in a large React app?
  • What happens between typing a URL and seeing a page?
  • How would you optimize a slow React page?
Phase 2 Exit Checklist
3

Peak β€” Weeks 6–7

Full mock interviews Β· hard problems Β· company-specific prep
Hard Problems β€” At Least One Per Week
#ProblemDiff
42Trapping Rain WaterHardGoogle
23Merge K Sorted ListsHardGoogle
297Serialize and Deserialize Binary TreeHardGoogle
127Word LadderHardGoogle
146LRU CacheMediumGoogle
Company-Specific Prep

Google

Notion

Phase 3 Exit Checklist

LeetCode Premium β€” Get It