Recursion and Dynamic Programming
Fibonacci with Memoization
Compute fib(n) recursively. Cache each fib(k) in a memo map so each
subproblem is solved at most once.
Algorithm
Canonical input n = 6 produces fib(6) = 8. Replay highlights every
memo write and every cache hit.
memoization
A `Dictionary<int, int>` keyed by `n` stores each completed subproblem. Before recursing, check `memo.ContainsKey(n)`: a hit returns immediately, a miss descends.
explicit memo state
The memo is threaded through the recursion as `Dictionary<int, int> memo` so the lesson stays about caching, not global state.
Basic Implementation
basic.cs
Replay: real traced execution (multi-file project)
using System;
using System.Collections.Generic;
class Program {
static int Fib(int n, Dictionary<int, int> memo) {
if (memo.ContainsKey(n)) {
return memo[n];
}
if (n < 2) {
memo[n] = n;
return n;
}
int value = Fib(n - 1, memo) + Fib(n - 2, memo);
memo[n] = value;
return value;
}
static void Main() {
Dictionary<int, int> memo = new Dictionary<int, int>();
int result = Fib(6, memo);
Console.WriteLine(result);
}
}
memo ← {}, action ← miss -> descend Fib(5)
12}13int value = Fib(n - 1, memo) + Fib(n - 2, memo);14memo[n] = value;values this step{}memomiss -> descend Fib(5)action6nmemo ← {}, action ← miss -> descend Fib(4)
12}13int value = Fib(n - 1, memo) + Fib(n - 2, memo);14memo[n] = value;values this step{}memomiss -> descend Fib(4)action5nmemo ← {}, action ← miss -> descend Fib(3)
12}13int value = Fib(n - 1, memo) + Fib(n - 2, memo);14memo[n] = value;values this step{}memomiss -> descend Fib(3)action4nmemo ← {}, action ← miss -> descend Fib(2)
12}13int value = Fib(n - 1, memo) + Fib(n - 2, memo);14memo[n] = value;values this step{}memomiss -> descend Fib(2)action3nmemo ← {}, action ← miss -> descend Fib(1)
12}13int value = Fib(n - 1, memo) + Fib(n - 2, memo);14memo[n] = value;values this step{}memomiss -> descend Fib(1)action2nmemo ← {1: 1}, action ← base 1; memo[1] = 1; return
12}13int value = Fib(n - 1, memo) + Fib(n - 2, memo);14memo[n] = value;values this step{1: 1}memobase 1; memo[1] = 1; returnaction1nmemo ← {0: 0, 1: 1}, action ← base 0; memo[0] = 0; Fib(2)=1; memo[2] = 1
12}13int value = Fib(n - 1, memo) + Fib(n - 2, memo);14memo[n] = value;values this step{0: 0, 1: 1}memobase 0; memo[0] = 0; Fib(2)=1; memo[2] = 1action0nmemo ← {0: 0, 1: 1, 2: 1, 3: 2}, action ← hit 1; Fib(3)=2; memo[3] = 2
12}13int value = Fib(n - 1, memo) + Fib(n - 2, memo);14memo[n] = value;values this step{0: 0, 1: 1, 2: 1, 3: 2}memohit 1; Fib(3)=2; memo[3] = 2action1nmemo ← {0: 0, 1: 1, 2: 1, 3: 2, 4: 3}, action ← hit 1; Fib(4)=3; memo[4] = 3
12}13int value = Fib(n - 1, memo) + Fib(n - 2, memo);14memo[n] = value;values this step{0: 0, 1: 1, 2: 1, 3: 2, 4: 3}memohit 1; Fib(4)=3; memo[4] = 3action2nmemo ← {0: 0, 1: 1, 2: 1, 3: 2, 4: 3, 5: 5}, action ← hit 2; Fib(5)=5; memo[5] = 5
12}13int value = Fib(n - 1, memo) + Fib(n - 2, memo);14memo[n] = value;values this step{0: 0, 1: 1, 2: 1, 3: 2, 4: 3, 5: 5}memohit 2; Fib(5)=5; memo[5] = 5action3nmemo ← {0: 0, 1: 1, 2: 1, 3: 2, 4: 3, 5: 5, 6: 8}, action ← hit 3; Fib(6)=8; memo[6] = 8
12}13int value = Fib(n - 1, memo) + Fib(n - 2, memo);14memo[n] = value;values this step{0: 0, 1: 1, 2: 1, 3: 2, 4: 3, 5: 5, 6: 8}memohit 3; Fib(6)=8; memo[6] = 8action4nstdout ← 8
20 int result = Fib(6, memo);21 Console.WriteLine(result);22}values this step8stdout8result
Complexity
- Time: O(n) with memoization (vs. O(2^n) without)
- Space: O(n) memo + O(n) call stack
Implementation notes
- The memo is a
Dictionary<int, int>allocated inMainand passed by reference through every recursive call, so all stack frames share one CLR-managed hash table that is reclaimed by GC. - The checked-in code intentionally uses
memo.ContainsKey(n)followed bymemo[n]instead ofTryGetValue, making memo hits replay-visible as a lookup and immediate return. Misses recurse untiln < 2, then writememo[n] = n. - Fibonacci values are
intvalues copied into the dictionary. AfterFib(n - 1, memo) + Fib(n - 2, memo)returns,memo[n] = valuerecords the completed subproblem; the trace separates those writes from later hits.