Chapter 51
HomeYou've seen naive Fibonacci (O(2ᴺ)) and memoised Fibonacci (O(N)). Now see all three approaches side by side, plus the bottom-up tabulation version. This is your template for every DP problem.
int fib(int n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
vectormemo(N + 1, -1); int fib(int n) { if (n <= 1) return n; if (memo[n] != -1) return memo[n]; return memo[n] = fib(n - 1) + fib(n - 2); }
int fib(int n) {
if (n <= 1) return n;
vector dp(n + 1);
dp[0] = 0; dp[1] = 1;
for (int i = 2; i <= n; i++)
dp[i] = dp[i - 1] + dp[i - 2];
return dp[n];
}
fn fib(n: usize) -> u64 {
if n <= 1 { return n as u64; }
let mut dp = vec![0u64; n + 1];
dp[0] = 0; dp[1] = 1;
for i in 2..=n {
dp[i] = dp[i - 1] + dp[i - 2];
}
dp[n]
}
💡 Tabulation always wins for Fibonacci
No recursion overhead, no cache-miss checking, no stack depth limit. Bottom-up is faster in practice for linear DP like Fibonacci. Top-down memoisation shines when the dependency graph is complex and you'd compute many unused states.
dp[i] depends on dp[i-1] and dp[i-2].