DSA Notes
Master the top-down DP approach using recursion with caching, Python decorators, manual memoization, and understanding stack overflow risks.
What is Memoization?
Memoization is a technique where you write a recursive solution and add a cache (memory) to store results of subproblems. When the function is called with the same arguments again, it returns the cached result instead of recomputing. The name comes from "memo" — you are writing yourself a note: "I already solved this, the answer is X."
The Pattern
| Without memoization | With memoization: |
| def solve(state) | cache = {} |
| if base_case | def solve(state): |
The function structure stays the same — you just wrap it with caching. This is why memoization is often called the "lazy" approach: you only solve subproblems that are actually needed.
Python's Built-in Memoization
Python makes memoization trivial with functools.lru_cache:
from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
if n <= 1:
return n
return fib(n - 1) + fib(n - 2)
print(fib(100)) # Instant! Without cache: would take billions of yearsThe @lru_cache(maxsize=None) decorator automatically caches all results. With maxsize=None, it caches unlimited entries (use a number to limit memory).
Manual Memoization
For more control or in languages without decorator support:
C++ Memoization Pattern
Real Example: Minimum Cost Climbing Stairs
Stack Overflow Risk
The biggest danger of top-down DP is stack overflow. Each recursive call adds a frame to the call stack. For problems with deep recursion (n > 1000 in Python, ~10000 in C++), you will crash.
Python Solution: Increase recursion limit
import sys
sys.setrecursionlimit(10**6) # Default is 1000But this is a band-aid. For very deep recursion (n > 10^5), switch to bottom-up tabulation.
Alternative: Iterative DFS with explicit stack
When to Use Memoization vs Tabulation
Prefer memoization when:
- Not all subproblems need to be solved (sparse state space)
- Natural recursive structure is clear
- Hard to determine computation order for tabulation
- Problem is easier to think about top-down
Prefer tabulation when:
- All subproblems will be needed
- Deep recursion would cause stack overflow
- Space optimization is desired (rolling array)
- You want iterative code (easier to debug)
Complexity Analysis
For memoized Fibonacci:
- Time: O(n) — each state computed exactly once, n states total
- Space: O(n) — cache stores n results + O(n) recursion stack
Key insight: memoization transforms exponential recursion into polynomial DP by ensuring each unique subproblem is solved only once.
Common Mistakes
- Forgetting base cases: Infinite recursion without proper termination
- Mutable default arguments: In Python,
def f(memo={})shares the dict across calls. UseNonedefault and initialize inside. - Wrong cache key: For 2D DP, cache key must include ALL state variables
- Not clearing cache: Between test cases in competitive programming, clear the memo
- Cache too large: For very large state spaces, consider tabulation with space optimization
Memoization with Multiple Arguments
Note: lru_cache requires hashable arguments. Lists and dicts cannot be used as arguments — convert to tuples.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Memoization (Top-Down Dynamic Programming).
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Data Structures & Algorithms topic.
Search Terms
data-structures-algorithms, data structures & algorithms, data, structures, algorithms, dynamic, programming, memoization
Related Data Structures & Algorithms Topics