Coding Interview: Patterns & DSA · Recursion, Backtracking & DP · Lesson 2 of 3
Dynamic programming: memoization
Dynamic programming (DP) applies when a problem has overlapping subproblems (the same smaller problem is solved many times) and optimal substructure (the best answer is built from best answers to subproblems). Memoization is top-down DP: write the natural recursion, then cache each subproblem's result so you never recompute it.
def fib(n, memo=None): if memo is None: memo = {} if n < 2: return n if n in memo: return memo[n] # reuse cached result memo[n] = fib(n - 1, memo) + fib(n - 2, memo) return memo[n]
Naive recursive Fibonacci is O(2^n) because it recomputes the same values exponentially often. Memoization collapses it to O(n): each of the n subproblems is computed once and then read from the cache.
- Spot DP: you are asked for a count of ways, a min/max, or a yes/no of feasibility, and choices depend on earlier choices.
- Define the state: what parameters uniquely identify a subproblem? That tuple is your cache key.
- Complexity = (number of distinct states) x (work per state). For 1-D Fibonacci that is
O(n) x O(1) = O(n).
Show your work onceMemoization is doing a hard homework problem, then writing the answer in the margin so when it reappears on the next page you copy it instead of redoing it. The recursion is unchanged — you just stop repeating yourself.
◆ Lock it in
- DP needs overlapping subproblems + optimal substructure.
- Memoization = recursion + a cache; each state is computed once.
- Runtime = #states x work-per-state; define the state first.
Feynman drill — say it out loudExplain how memoization turns exponential Fibonacci into O(n) without changing the recurrence.
Step 1 rate your confidence · Step 2 pick your answer
Memoization improves naive recursive Fibonacci from O(2^n) to O(n) because:
Step 1 — how sure are you?