💡
DP & Greedy
Memoization · Tabulation · Fibonacci · stairs
20. Dynamic Programming — Basics
DP turns exponential brute force into polynomial-time solutions by storing answers to subproblems. Learn the two flavors (top-down memoization vs bottom-up tabulation) on classic problems.
DPmemoizationtabulation
Duration
⏱ ~1 hour
Level
📊 Intermediate
Prerequisite
🎯 Recursion + iteration
OUTCOME
Identify a DP problem and code both top-down and bottom-up solutions.
What you'll learn
- 1Explain the two DP approaches (memoization vs tabulation)
- 2Find the recurrence and the base case
- 3Apply DP to Fibonacci, stairs, coin change
Overview
If a problem has 'optimal substructure' (the answer depends on answers to smaller subproblems) and 'overlapping subproblems' (the same subproblem is asked many times), DP can convert exponential brute force to polynomial.
Core Concepts
1. Top-down (memoization)
python
from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
if n < 2: return n
return fib(n-1) + fib(n-2)
# Or manual:
memo = {}
def fib(n):
if n < 2: return n
if n in memo: return memo[n]
memo[n] = fib(n-1) + fib(n-2)
return memo[n]2. Bottom-up (tabulation)
python
def fib(n):
if n < 2: return n
dp = [0] * (n + 1)
dp[1] = 1
for i in range(2, n + 1):
dp[i] = dp[i-1] + dp[i-2]
return dp[n]
# Space-optimized (only last 2 values needed):
def fib(n):
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return a3. Comparison
| Approach | Pros | Cons |
|---|---|---|
| Memoization (top-down) | Closer to the recursive intuition; computes only needed subproblems | Recursion depth, function call overhead |
| Tabulation (bottom-up) | No recursion limit; iterative; often faster | Sometimes overcomputes |
4. Climbing stairs
python
# Reach step n by taking 1 or 2 steps at a time
def stairs(n):
if n <= 2: return n
dp = [0] * (n + 1)
dp[1] = 1; dp[2] = 2
for i in range(3, n + 1):
dp[i] = dp[i-1] + dp[i-2]
return dp[n]5. Coin change (minimum coins)
python
def min_coins(coins, target):
INF = float('inf')
dp = [INF] * (target + 1)
dp[0] = 0
for amount in range(1, target + 1):
for c in coins:
if c <= amount:
dp[amount] = min(dp[amount], dp[amount - c] + 1)
return dp[target] if dp[target] != INF else -1Examples
Example 1 — src/01_fibonacci_memo.py
Fibonacci with lru_cache memoization.
Example 2 — src/02_fibonacci_tab.py
Fibonacci bottom-up + space-optimized.
Example 3 — src/03_climbing_stairs.py
Stairs with cost constraints (BOJ 2579).
Example 4 — src/04_coin_change.py
Coin change minimum coins.
Common Mistakes
- Recursion depth blow-up with memoization on N=10⁶. Use tabulation.
- Forgetting base cases — dp[0], dp[1] need explicit initialization.
- Off-by-one in dp size: `dp = [0] * n` vs `dp = [0] * (n + 1)`.
- Confusing 'min coins' with 'number of ways to make change' — different recurrences.
Recap
- DP = recurrence + base case + storage.
- Top-down (memoize) for intuitive code; bottom-up (tabulate) for performance.
- Always state the recurrence in plain English before coding.
Try It
- BOJ 2579 (Climbing stairs).
- BOJ 1463 (Make 1).
- BOJ 11726 (2×n tiling).
Example code / lecture materials
All lecture materials and example code are openly available on GitHub.
View on GitHub ↗