Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Dynamic Programming

Solve complex optimization problems by remembering smaller results. This notebook covers core ideas, worked examples (coin change & knapsack), lightweight runnable cells, and exercises to practice reconstruction and memoization.

Learning goals

  • Explain optimal substructure and overlapping subproblems.

  • Implement tabulation and memoization patterns.

  • Reconstruct solutions (not just counts) for coin-change and knapsack.

# 0/1 Knapsack — worked example (small)

```python
# Items: (value, weight)
items = [(6,2),(10,3),(12,4)]
max_w = 7
n = len(items)
# DP table: dp[i][w] = max value using first i items and capacity w
dp = [[0]*(max_w+1) for _ in range(n+1)]
keep = [[False]*(max_w+1) for _ in range(n+1)]
for i in range(1,n+1):
    val, wt = items[i-1]
    for w in range(max_w+1):
        if wt <= w and dp[i-1][w-wt] + val > dp[i-1][w]:
            dp[i][w] = dp[i-1][w-wt] + val
            keep[i][w] = True
        else:
            dp[i][w] = dp[i-1][w]
# reconstruct
w = max_w
picked = []
for i in range(n,0,-1):
    if keep[i][w]:
        picked.append(items[i-1])
        w -= items[i-1][1]
print('Max value:', dp[n][max_w])
print('Picked items:', picked)
```

Exercises

  1. Implement dp_min_coins(coins, amount) that returns the optimal coin multiset (not just count).

  2. Modify the Fibonacci example to use memoization (recursion + cache) and measure time vs iterative DP for n=30.

  3. Implement the 0/1 knapsack DP and reconstruct selected items for a small test case.

Hints and solution reveals are in the `solutions` folder. Start with small amounts and item sizes.

Summary / Key Takeaway

  • Dynamic programming identifies overlapping subproblems and reuses solutions via memoization or tabulation.

  • Use DP when optimal substructure and overlapping subproblems are present; prefer greedy when a local choice is provably safe.

  • Next: we’ll move to data loading and wrangling, where DP-style caching patterns appear in memoized feature computations.

Dynamic Programming

Solving Complex Problems by Reusing Smaller Results

def fibonacci(n):
    if n <= 1:
        return n
    dp = [0, 1]
    for index in range(2, n + 1):
        dp.append(dp[index - 1] + dp[index - 2])
    return dp[n]

print(fibonacci(8))
21

Core Explanation

Dynamic programming is useful when:

  • a problem can be broken into smaller overlapping subproblems

  • solving the same subproblem repeatedly would waste time

  • storing previous results helps improve efficiency

Worked Example

The Fibonacci sequence is a common teaching example because the naive recursive approach repeats the same subproblems many times.

Why dynamic programming helps here

Instead of recomputing earlier Fibonacci values repeatedly, we build them once and reuse them.

Business and ML Connection

Dynamic programming ideas appear in optimization, scheduling, planning, sequence analysis, and decision-making problems.

Examples include:

  • budgeting under constraints

  • resource allocation

  • route optimization variants

  • sequence alignment and structured prediction

Quick Quiz

Why is dynamic programming often faster than naive repeated computation?

Because it stores and reuses intermediate resultsCorrect. Reuse avoids recomputing overlapping subproblems.
Because it never uses loopsDynamic programming often uses loops.
Because it avoids all memory usageIt usually uses extra memory to save time.
values = [3, 7, 2, 9]
best = [0]
for value in values:
    best.append(best[-1] + value)
print(best[-1])
21

Exercises

  1. Explain dynamic programming in your own words.

  2. Identify one problem where overlapping subproblems may appear.

  3. Compare greedy thinking and dynamic programming conceptually.

Quick Summary
  • dynamic programming solves overlapping subproblems efficiently

  • it stores intermediate answers for reuse

  • it is especially useful in optimization and planning problems

Final Note

Dynamic programming is a powerful reminder that good algorithm design often comes from noticing structure in a problem, not just from writing more code.

8. Interactive Code

Expected output
[0, 1, 1, 2, 3, 5, 8]
Expected output
7
4

9. Guided Practice

What is a defining idea in dynamic programming?

Ignore previous results completelyDynamic programming reuses earlier results.
Break a problem into overlapping subproblems and store resultsCorrect. Reuse of stored sub-results is central.
Use only graphsDynamic programming is not limited to graphs.
Always sort the input firstSorting is not a defining requirement.

Why is the Fibonacci example a classic dynamic-programming illustration?

Because it has no repeated structureIt does have repeated subproblems.
Because later values reuse earlier computed valuesCorrect. Each value builds from prior stored values.
Because it requires a queueA queue is not the point here.
Because it removes duplicates from a setThat is unrelated.