1@cache2def fib(n):3 if n < 2: return n4 return fib(n-1) + fib(n-2)5t = [0] * 86t[1] = 17for i in range(2, 8):8 t[i] = t[i-1] + t[i-2]t[0]t[1]t[2]t[3]t[4]t[5]t[6]t[7]134
Code card: the recursive function and the table loopMemory cells: the table t, filled left to rightTags: how often a cell was worked out, or the last coin usedArrows: the earlier cells a new cell readsThe row of cells is the table. When a cell is filled, arrows rise from the cells it reads and value tokens glide along them into it, then its value fades in. Plain recursion works out the same Fibonacci answers again and again (the tags count it: fib(7) makes 41 calls, fib(30) 2,692,537). Memoization and tabulation both store each answer once. The same table idea finds the fewest coins: with coins 1, 3 and 4, the amount 6 needs only two (3 + 3), not the three that taking the biggest coin first uses.

Recomputing

  1. Fibonacci numbers start 0, 1, and each next one is the sum of the two before it: 0, 1, 1, 2, 3, 5, 8, 13. So fib(7) needs fib(6) and fib(5). The arrows show which cells an answer uses.

Store answers

Coin change

Try it in Python

;; step 1/12 · Answers built from smaller ones
def fib(n):
    if n < 2: return n
    return fib(n-1) + fib(n-2)

>>> [fib(n) for n in range(8)]
[0, 1, 1, 2, 3, 5, 8, 13]

Plain recursion calls fib(n) 2 × F(n+1) − 1 times in total (the Leonardo numbers): 41 for fib(7) and 2 × 1,346,269 − 1 = 2,692,537 for fib(30). The ratio between one count and the next tends to the golden ratio, about 1.618. @cache arrived in Python 3.9 and is the same as @lru_cache(maxsize=None). For fib(30), cache_info() reports 31 misses (answers worked out) and 28 hits (answers read back). Memoized recursion still goes one call deeper for each n. CPython stops at about 1000 nested calls by default (sys.getrecursionlimit()), so fib(5000) with @cache raises RecursionError, while the table loop has no such limit.