Recursion, call trees and memoisation
See recursion as a tree of calls, work out its cost from the tree, fix repeated work with memoisation, and recognise the recursion patterns behind famous algorithms.
The cost of recursion = number of calls × work per call
long calls = 0; // counts every call long Fib(int n){ calls++; if (n <= 1) return n; // base cases: Fib(0) = 0, Fib(1) = 1 return Fib(n - 1) + Fib(n - 2); // two recursive calls} Console.WriteLine($"Fib(30) = {Fib(30)}, calls = {calls:N0}");Fib(30) = 832040, calls = 2,692,537
Memoisation: remember answers you already have
static long Fib(int n, Dictionary<int, long> memo){ if (n <= 1) return n; if (memo.TryGetValue(n, out long known)) return known; // already solved long result = Fib(n - 1, memo) + Fib(n - 2, memo); memo[n] = result; // remember it return result;} Console.WriteLine(Fib(90, new Dictionary<int, long>()));2880067194370816120
Or skip recursion: build up from the bottom
static long Fib(int n){ long a = 0, b = 1; // Fib(0), Fib(1) for (int i = 0; i < n; i++) (a, b) = (b, a + b); // slide the window forward return a;} Console.WriteLine(Fib(90));2880067194370816120
| Version | Time | Extra space |
|---|---|---|
O(2ⁿ) | O(n) stack | |
O(n) | O(n) memo + stack | |
O(n) | O(1) |
Recursion patterns you will meet again
| Pattern | Each call… | Cost | Example |
|---|---|---|---|
O(n) | |||
O(log n) | |||
O(n log n) | |||
O(2ⁿ) |
static long Power(long x, int n){ if (n == 0) return 1; long half = Power(x, n / 2); // ONE recursive call on n/2 return n % 2 == 0 ? half * half : half * half * x;} Console.WriteLine(Power(2, 10));Console.WriteLine(Power(3, 5));1024 243
Ways(int n) that returns how many different ways there are to reach step n (Ways(0) = 1, Ways(1) = 1). Make it fast enough for n = 50 using memoisation.
Show a hint
long[] of size n + 1.
Show the solution
static long Ways(int n, long[] memo){ if (n <= 1) return 1; if (memo[n] != 0) return memo[n]; return memo[n] = Ways(n - 1, memo) + Ways(n - 2, memo);} Console.WriteLine(Ways(10, new long[11]));Console.WriteLine(Ways(50, new long[51]));89 20365011074
Remember
Draw recursion as a call tree: cost = number of calls × work per call. Two calls on n − 1 give an exponential tree; one call on n / 2 gives O(log n). Memoisation stores each answer the first time and turns repeated work into lookups. Bottom-up loops can give the same speed with O(1) space; this leads to dynamic programming.