Dynamic Programming — Introduction#
DP turns exponential recursion into polynomial tabulation by reusing subproblem answers. Full problem catalog: 13. Dynamic Programming (84 problems).
When DP applies#
Both must hold:
- Optimal substructure — optimal solution uses optimal subsolutions.
- Overlapping subproblems — same subproblem solved many times in naive recursion.
If only (1) holds and choices are locally optimal → try Greedy first. See Greedy vs DP.
Five-step framework#
- Define state — what does
dp[i]ordp[i][j]mean? - Recurrence — how does
dp[i]depend on smaller indices? - Base cases — smallest subproblems with known answers.
- Order — fill table so dependencies are ready.
- Answer — which cell holds the final result? Reconstruct path if needed.
Top-down vs bottom-up#
| Top-down (memo) | Bottom-up (tabulation) | |
|---|---|---|
| Code | @cache on recursion |
Nested loops |
| Space | O(states) + stack | O(states) table |
| Best when | Sparse states, quick to write | Need full table, space optimize |
from functools import cache
@cache
def dp(i: int) -> int:
if i == 0:
return base
return min(dp(i - 1), dp(i - 2)) + cost[i]
Classic families#
| Family | State hint | Pattern doc |
|---|---|---|
| 0/1 Knapsack | include/exclude item | DP § Knapsack |
| Unbounded knapsack | unlimited use | Coin Change |
| LCS / edit distance | two string indices | DP § LCS |
| Grid path | (row, col) |
DP § 2D Grid |
| Linear sequence | dp[i] from prior |
House Robber, LIS |
| Tree DP | return per subtree | House Robber III, Cameras |
| State machine | hold/sell/cooldown | Stock problems |
| Bitmask | subset as mask | TSP, partition |
Space optimization#
When dp[i] only needs dp[i-1] and dp[i-2]:
Knapsack: one row, iterate right-to-left when updating in place.
Common pitfalls#
- Greedy works — don't over-DP (e.g. activity selection → greedy).
- State too big — if dimensions exceed ~10⁶, look for structure or math.
- Wrong order — filling before dependencies are ready gives wrong answers.
- Forgetting base cases — empty string, zero capacity, leaf nodes.
Starter problems#
| Problem | LC | Why start here |
|---|---|---|
| Climbing Stairs | 70 | 1D recurrence |
| House Robber | 198 | include/exclude |
| Coin Change | 322 | unbounded knapsack |
| Longest Increasing Subsequence | 300 | 1D + patience sorting |
| Edit Distance | 72 | 2D classic |
All have full solutions in 13. Dynamic Programming.
Related#
- Recursion — base case and call stack
- Greedy vs DP
- Backtracking — when you need all solutions, not optimal count
- Complexity