Dynamic programming (DP) is a fancy name for a simple idea: don't solve the same subproblem twice. When a problem breaks into overlapping subproblems, you solve each one once, remember the answer, and reuse it.
Two ingredients:
The naive recursive Fibonacci has both: fib(n) = fib(n-1) + fib(n-2), and it
recomputes fib(2) an exponential number of times. DP fixes the recomputation.
memo = {}
function fib(n):
if n < 2:
return n
if n in memo:
return memo[n]
memo[n] = fib(n-1) + fib(n-2)
return memo[n]
That one cache turns O(2ⁿ) into O(n): each subproblem is computed once.
DP collapses exponential brute force into polynomial time. The hard part is never the
caching — it's defining the subproblem: what does solve(x) mean, what are its
arguments, and how does it combine smaller answers? Nail that, and memoization is
mechanical. The next lesson contrasts the two standard ways to implement it.