"Memoization is the gentlest way into dynamic programming: write the obvious recursion, then add a cache. Often it's a one-line change that turns an exponential disaster into a linear-time solution."
Recursion Plus a Cache
Memoization is top-down DP: you write the natural recursive solution — the one that directly mirrors the problem — and add a cache that remembers each subproblem's answer the first time it's computed. Every later request for that same subproblem is an instant lookup instead of a recomputed subtree. It's called top-down because you start at the big problem and recurse down toward the base cases, caching results as the recursion unwinds. The beauty: you don't have to redesign anything — you take a correct (but slow) recursion and make it fast by remembering.
The Cache Key Is the State
The one concept to nail: the cache is keyed by the state of the subproblem — which, conveniently, is exactly the function's arguments. fib(7)'s state is 7; edit_distance(i, j)'s state is the pair (i, j). Two calls with the same arguments are the same subproblem and must return the same answer, so the arguments make a perfect cache key. In Python this is almost free: decorate the function with @functools.cache (or @lru_cache) and the caching happens automatically, keyed by the arguments. A correct recursion becomes top-down DP with literally one line.
The Trade-Offs
Memoization's strengths: it's the easiest DP to write (just cache a recursion you already trust), and it's lazy — it only ever computes the subproblems actually needed to answer your query, skipping unreachable states a bottom-up table would waste time filling. Its weaknesses: it rides the call stack, so very deep state chains can hit the recursion limit (the Recursion-track caution), and the cache carries some memory and lookup overhead. For most problems, memoization is the right first move — reach for the bottom-up table (next lesson) only when depth or space forces it.
Pippa's Confession
@cache above my existing recursive function and it went from timing out to instant. I felt slightly cheated — that's dynamic programming? But that's the honest truth of top-down DP: if your recursion is correct, memoization is often a single decorator away. The hard part was never the caching; it was writing the right recurrence, which I'd already done.