C.W.K.
Stream
Lesson 01 of 06 · published

What Dynamic Programming Really Is

~11 min · dynamic-programming, intuition, conditions

Level 0Curious Beginner
0 XP0/85 lessons0/19 achievements
0/100 XP to next level100 XP to go0% complete
"Dynamic programming has the scariest name in algorithms and one of the simplest ideas: don't solve the same subproblem twice. Richard Bellman literally picked the name to sound impressive to a budget committee. Don't let it intimidate you."

The Name Is a Marketing Trick

'Dynamic programming' sounds like advanced sorcery. It isn't. Bellman, who coined it in the 1950s, later admitted he chose 'dynamic' because it sounded exciting and 'programming' to disguise mathematical research from a cost-cutting boss. The actual idea is humble: solve each subproblem once, store the answer, and reuse it instead of recomputing. You already did this in the recursion track when memoizing Fibonacci collapsed O(2ⁿ) to O(n). That was dynamic programming. You've been doing DP without the scary label.

The Two Conditions

A problem yields to DP when it has both of these:

  • Overlapping subproblems: a naive recursion ends up solving the same smaller problems over and over (the repeated subtrees in the Fibonacci recursion tree). This is what makes caching pay off — if every subproblem were unique, there'd be nothing to reuse.
  • Optimal substructure: the optimal solution to the whole problem is built from optimal solutions to its subproblems. (The shortest path from A to C through B uses the shortest A-to-B and B-to-C paths.) This is what lets you combine sub-answers into the full answer.

Both present → DP applies. Subproblems don't overlap → it's just divide-and-conquer (nothing to cache). No optimal substructure → you can't safely build the answer from parts, and DP won't work.

Dynamic programming = solve each subproblem once and reuse the answer. It applies when a problem has overlapping subproblems (the same smaller problems recur, so caching helps) AND optimal substructure (the best whole is built from best parts). It's 'careful brute force' — recursion that doesn't repeat itself.

DP vs Divide-and-Conquer

The distinction from the last track is precise. Divide-and-conquer (merge sort) splits into subproblems that are independent — the two halves share nothing, so there's nothing to cache. Dynamic programming splits into subproblems that overlap — the same sub-answers are needed in many places, so caching them is the entire win. Same recursive instinct; the difference is whether the subproblems repeat. When they repeat, you stop recomputing and start remembering. That shift from 'recompute' to 'remember' is the whole discipline.

Pippa's Confession

'Dynamic programming' terrified me for years — it sounded like a topic for people smarter than me. Then Dad told me the name was Bellman's deliberate camouflage, and showed me that the memoized Fibonacci I'd already written was DP. The fear evaporated. The lesson generalized hard: an intimidating name often hides a simple idea dressed up, and the move is to find the plain sentence underneath. For DP, that sentence is just 'don't compute the same thing twice.'

Code

Memoized Fibonacci IS dynamic programming·python
# You already wrote DP in the recursion track. Here it is, named.
from functools import lru_cache

# NAIVE: overlapping subproblems recomputed -> O(2^n).
def fib_naive(n):
    if n < 2: return n
    return fib_naive(n - 1) + fib_naive(n - 2)

# DYNAMIC PROGRAMMING (top-down): solve each subproblem ONCE, reuse it.
@lru_cache(maxsize=None)
def fib_dp(n):
    if n < 2: return n
    return fib_dp(n - 1) + fib_dp(n - 2)   # same recurrence, now cached

print(fib_dp(50))   # 12586269025 — instant

# The two DP conditions, checked on Fibonacci:
#   Overlapping subproblems? YES — fib(3), fib(4)... recur all over the tree.
#   Optimal substructure?     YES — fib(n) is built directly from fib(n-1),fib(n-2).
# Both hold -> DP applies. The ONLY change from naive is: remember each answer.

External links

Exercise

For each, decide whether it's a DP candidate by checking the two conditions: (1) computing n! — does it have overlapping subproblems? (2) the number of distinct paths from the top-left to bottom-right of a grid moving only right/down. Explain your verdict for each in terms of overlapping subproblems and optimal substructure.
Hint
n! has optimal substructure but NO overlapping subproblems (each factorial(k) is computed once even naively) — so it's plain recursion, not DP. Grid paths: paths(i,j) = paths(i-1,j) + paths(i,j-1), and the same (i,j) subproblems recur across many routes — overlapping + optimal substructure → a textbook DP.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.