Analyzing Recursive Algorithm Complexity — Master Theorem, Recursion Tree, Substitution
Fast recall
Quick revision
Core answer
a is the number of sub-problems and n/b is each sub-problem's size. The three master-theorem cases: Case 1 — if f(n) = O(n^(log_b(a) − ε)), then T(n) = Θ(n^log_b(a)) (the leaves dominate). Case 2 — if f(n) = Θ(n^log_b(a)), then T(n) = Θ(n^log_b(a) · log n) (balanced). Case 3 — if f(n) = Ω(n^(log_b(a) + ε)) with regularity, then T(n) = Θ(f(n)) (the root work dominates). Examples: Merge sort T(n) = 2T(n/2) + O(n) — a=2, b=2, log_b(a) = 1, f(n) = n = Θ(n^1) → Case 2 → Θ(n log n). Binary search T(n) = T(n/2) + O(1) — a=1, b=2, log_b(a) = 0, f(n) = 1 = Θ(n^0) → Case 2 → Θ(log n). Naive Fibonacci T(n) = T(n-1) + T(n-2) + O(1) — NOT a master-theorem form (doesn't divide into equal sub-problems); use recursion tree to see branching factor ≈2 per level, depth n → O(2^n) (more precisely O(φ^n) where φ ≈ 1.618). Key intuition: fewer sub-problems or smaller size = cheaper; more or bigger = more expensive. Memoization or iteration converts exponential recursion to polynomial.Whether the candidate can write a recurrence from code, solve it with the master theorem OR recursion tree, and recognize common patterns (merge sort, binary search, Fibonacci)
Trying to apply master theorem to non-master-form recurrences (like Fibonacci). Forgetting to identify f(n). Confusing the base of the log in master theorem
Know all three master-theorem cases with examples, explain recursion tree intuitively, mention that Fibonacci with memoization is O(n), reference T(n) = 2T(n/2) + O(n) as 'the merge sort recurrence'
Interview-ready guide
Interview answer
To analyze a recursive algorithm, write a recurrence that expresses its running time on size n in terms of sub-problems, then solve it.
Three standard techniques
1. Substitution method
- Guess a bound
- Prove by induction
- Used when you already suspect the answer
2. Recursion tree
- Draw the tree of recursive calls
- Compute work at each level
- Sum up
- Intuitive and general — works for most recurrences
3. Master theorem
- Plug-and-play formula for
T(n) = aT(n/b) + f(n)form a= number of sub-problemsn/b= size of each sub-problemf(n)= non-recursive work per call
Master theorem — three cases
- Compute c = log_b(a)
- Case 1: f(n) polynomially smaller than n^c → T(n) = Θ(n^c). Leaves dominate.
- Case 2: f(n) = Θ(n^c) → T(n) = Θ(n^c log n). Balanced.
- Case 3: f(n) polynomially bigger than n^c → T(n) = Θ(f(n)). Root dominates.
Classic examples
Merge sort: T(n) = 2T(n/2) + O(n)
- a=2, b=2, c = log_2(2) = 1
- f(n) = n = Θ(n^1) → Case 2
- T(n) = O(n log n)
Binary search: T(n) = T(n/2) + O(1)
- a=1, b=2, c = 0
- f(n) = 1 = Θ(n^0) → Case 2
- T(n) = O(log n)
Strassen's matrix multiply: T(n) = 7T(n/2) + O(n²)
- a=7, b=2, c ≈ 2.807
- f(n) = n² is polynomially smaller than n^2.807 → Case 1
- T(n) = O(n^2.807) — beats naive O(n³)
Karatsuba multiplication: T(n) = 3T(n/2) + O(n)
- a=3, b=2, c ≈ 1.585
- Case 1 → T(n) = O(n^1.585) — beats naive O(n²)
Naive Fibonacci — NOT master theorem form
- T(n) = T(n-1) + T(n-2) + O(1)
- Sub-problems shrink by additive constant, not multiplicative factor
- Use recursion tree: branches into 2 per level, depth n
- T(n) = O(2^n), more tightly O(φ^n) ≈ O(1.618^n)
- Memoization reduces to O(n)
- Matrix exponentiation: O(log n)
Recursion tree — when master theorem doesn't apply
Draw the tree:
- Merge sort: log n levels, O(n) work per level → O(n log n)
- Binary search: log n levels, O(1) per level → O(log n)
- Fibonacci: n levels, branches doubling → O(2^n)
- Linear recursion T(n) = T(n-1) + O(1): n levels, O(1) each → O(n)
Memorize these common recurrences
- T(n) = T(n-1) + O(1) → O(n)
- T(n) = T(n-1) + O(n) → O(n²)
- T(n) = T(n/2) + O(1) → O(log n)
- T(n) = T(n/2) + O(n) → O(n)
- T(n) = 2T(n/2) + O(1) → O(n)
- T(n) = 2T(n/2) + O(n) → O(n log n)
- T(n) = 2T(n-1) + O(1) → O(2^n) (Tower of Hanoi)
- T(n) = T(n-1) + T(n-2) + O(1) → O(φ^n)
Memoization converts exponential to polynomial
- Naive Fib: O(2^n) due to overlapping sub-problems
- Memoized Fib: O(n) — each sub-problem computed once
- Tabulated Fib with rolling vars: O(n) time, O(1) space
- This is the heart of dynamic programming
Space complexity — don't forget the stack
- Merge sort: O(n) aux + O(log n) stack = O(n)
- Binary search: O(log n) stack
- Naive Fib: O(n) stack
- Quicksort: O(log n) avg, O(n) worst
- Tail recursion: Java does NOT optimize — stack still grows
- For deep recursion, convert to iterative to avoid StackOverflowError
Common traps
1. Applying master theorem to non-master form
- Fibonacci — use recursion tree
- Tower of Hanoi — use recursion tree
2. Forgetting the regularity condition in Case 3
- a·f(n/b) ≤ k·f(n) for some k < 1
- Usually holds for polynomials
3. Confusing log base
- log_b(a) — log of a base b
- Don't confuse with log n (which is base 2 by convention in CS)
4. Forgetting space complexity
- Recursion always uses O(depth) stack space
- Can cause StackOverflow even if time is fine
Recommendation: When given a recursive algorithm, write the recurrence first — identify a (number of sub-problems), b (shrinkage factor), and f(n) (non-recursive work). If the form is T(n) = aT(n/b) + f(n), apply master theorem with c = log_b(a) and the three cases. If not (like Fibonacci or Tower of Hanoi), use the recursion tree — draw the levels, compute work per level, sum up. Memorize the common recurrences — merge sort's O(n log n), binary search's O(log n), Fibonacci's O(2^n) — these appear constantly. When you see an exponential recurrence with overlapping sub-problems, reach for memoization to convert to polynomial — this is the essence of dynamic programming. Always compute space complexity too: recursion is O(depth) stack space, and Java does not optimize tail calls — deep recursion can StackOverflow. For interviews, practice deriving the recurrence from the code in one pass: read the function, count sub-calls, count non-recursive work, write the recurrence, apply master theorem. The most common mistake is trying to force master theorem onto non-master-form recurrences; when in doubt, draw the tree.
Analyzing Recursive Algorithm Complexity — Master Theorem, Recursion Tree, Substitution
Direct Answer
To analyze a recursive algorithm, write a recurrence relation that expresses its running time on input size n in terms of its running time on smaller sub-problems, then solve the recurrence. Three standard techniques: (1) Substitution method — guess a bound, prove it by induction (used when you already suspect the answer). (2) Recursion tree — draw the tree of recursive calls, compute the work at each level, sum up (intuitive and works for most practical cases). (3) Master theorem — a formula that solves recurrences of the form T(n) = aT(n/b) + f(n), where a is the number of sub-problems and n/b is each sub-problem's size. The three master-theorem cases: Case 1 — if f(n) = O(n^(log_b(a) − ε)), then T(n) = Θ(n^log_b(a)) (the leaves dominate). Case 2 — if f(n) = Θ(n^log_b(a)), then T(n) = Θ(n^log_b(a) · log n) (balanced). Case 3 — if f(n) = Ω(n^(log_b(a) + ε)) with regularity, then T(n) = Θ(f(n)) (the root work dominates). Examples: Merge sort T(n) = 2T(n/2) + O(n) — a=2, b=2, log_b(a) = 1, f(n) = n = Θ(n^1) → Case 2 → Θ(n log n). Binary search T(n) = T(n/2) + O(1) — a=1, b=2, log_b(a) = 0, f(n) = 1 = Θ(n^0) → Case 2 → Θ(log n). Naive Fibonacci T(n) = T(n-1) + T(n-2) + O(1) — NOT a master-theorem form (doesn't divide into equal sub-problems); use recursion tree to see branching factor ≈2 per level, depth n → O(2^n) (more precisely O(φ^n) where φ ≈ 1.618). Key intuition: fewer sub-problems or smaller size = cheaper; more or bigger = more expensive. Memoization or iteration converts exponential recursion to polynomial.
Common Mistakes & Pitfalls
Trying to apply master theorem to non-master-form recurrences (like Fibonacci). Forgetting to identify f(n). Confusing the base of the log in master theorem
Check your understanding
Answer these without looking back at the article.
- Why can't master theorem solve Fibonacci's recurrence?
- How does memoization change naive Fibonacci from O(2^n) to O(n)?
- What's the difference between the three cases of the master theorem?
- Why does Java not optimize tail recursion?
- How do you choose between recursion tree and substitution method?
Related interview prep categories
1Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.