Chapter 38
HomeThe naive Fibonacci recalculates the same values hundreds of thousands of times. Memoization caches each result the first time it's computed — subsequent calls return the cached value in O(1). Result: O(2ᴺ) → O(N).
Clean, elegant, and catastrophically slow. Each call spawns two more.
int fib(int n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
// fib(40) → 102,334,155 (331 million calls)
// fib(100) → never finishes in your lifetime
fn fib(n: u64) -> u64 {
if n <= 1 { return n; }
fib(n - 1) + fib(n - 2)
}
Add a cache (an array or map). Before recursing, check the cache. After computing, store in the cache. The same value is never computed twice.
long long fib_memo(int n, vector<long long>& memo) {
if (n <= 1) return n;
if (memo[n] != -1) return memo[n]; // cached → return
memo[n] = fib_memo(n - 1, memo) + fib_memo(n - 2, memo);
return memo[n];
}
// Usage:
vector<long long> memo(n + 1, -1);
cout << fib_memo(n, memo) << "\n";
fn fib_memo(n: usize, memo: &mut Vec<Option<u64>>) -> u64 {
if n <= 1 { return n as u64; }
if let Some(val) = memo[n] { return val; }
let val = fib_memo(n - 1, memo) + fib_memo(n - 2, memo);
memo[n] = Some(val);
val
}
// Usage:
let mut memo = vec![None; n + 1];
println!("{}", fib_memo(n, &mut memo));
💡 Top-down vs bottom-up
This is top-down DP: start with the full problem, recurse
down, cache results. The alternative is bottom-up (iterative):
fill memo[0], memo[1], up to memo[N].
Both are O(N). Top-down is often easier to write; bottom-up avoids recursion
overhead. You'll see both in Phase 7 (Dynamic Programming).
// Speed comparison: // fib(40) fib(100) // Naive: 331M calls ∞ // Memoized: 79 calls 199 calls // Bottom-up: 40 iterations 100 iterations
Memoization works for any recursive function with overlapping subproblems. The pattern is always the same:
1. Identify the state
What parameters define a unique subproblem? (e.g. n in Fibonacci)
2. Create a cache
An array or map keyed by state. Use a sentinel value (-1 or None) for "not computed."
3. Check before compute
If the cache has the answer, return it. Otherwise compute, store, return.