Memoisation: caching with a dictionary
Put a dictionary in front of the function: if the arguments have been seen, return the stored answer. That collapses an exponential call tree into a linear walk without changing the recurrence at all. functools.lru_cache is this, with a size bound and thread safety.
Overview
Why it works at all
Naive recursion on overlapping subproblems recomputes the same values an exponential number of times. Memoisation does not make each call faster; it makes the repeated ones disappear, so the work drops to the number of distinct subproblems.
This is dynamic programming from the top down. The bottom-up table computes the same values in a loop with no call stack — same complexity, and see dynamic programming for both directions side by side.
Step through it
What to watch
- Call counts diverge fast — the gap is exponential against linear.
- The recurrence is identical in both versions.
- The cache is what turns repeated subproblems into one lookup.
Say this out loud
"Memoise it - a dict keyed on the arguments. The recursion is unchanged; it just stops descending into subtrees it has already solved. In Python that's @lru_cache, which also bounds the size so it can't grow forever."