Introduction to Dynamic Programming

This lesson defines dynamic programming (DP) as an optimization technique, explains optimal substructure and overlapping subproblems, contrasts DP with greedy and divide-and-conquer, compares memoization vs tabulation, and maps classic DP problems to real-world applications.

What is Dynamic Programming?

Dynamic programming is a method for solving complex problems by breaking them into simpler overlapping subproblems, storing the results of those subproblems, and reusing them instead of recomputing. The word dynamic refers to the table of stored answers built over time—not to runtime speed by itself.

DP is not a single algorithm like binary search; it is a problem-solving paradigm. You define a recurrence (how a larger answer depends on smaller ones), identify a state (what you must remember), and fill or cache a table of optimal values.

Schematic: Fibonacci with overlap

Naive recursion recomputes the same values many times. DP stores each fib(k) once:

fib(5)
 ├── fib(4)          fib(3)  ← fib(3) computed again without DP
 │    ├── fib(3)     fib(2)
 │    │    fib(2) fib(1)
 │    └── fib(2) fib(1)
 └── fib(3)  ← duplicate subtree

With DP: fib(0)…fib(5) stored once → O(n) time

The Two DP Properties

A problem is a strong DP candidate when both properties hold:

1. Optimal Substructure

An optimal solution to the full problem can be built from optimal solutions to its subproblems.

Example:

  • Shortest path in a graph
  • Best way to pack a knapsack of capacity W uses the best answers for smaller capacities
  • Minimum cost to reach position i depends on minimum cost to reach i-1 and i-2

2. Overlapping Subproblems

The same subproblem appears many times in the recursion tree.

Examples:

  • Fibonacci numbers
  • Edit distance
  • Coin change
  • Longest common subsequence
Note: If subproblems are disjoint—like merge sort partitions—divide-and-conquer alone is enough; classic DP is less useful.

DP vs Greedy vs Divide-and-Conquer

All three decompose problems, but the guarantees and storage differ:

Approach Idea Stores sub-answers? Typical signal
Divide & Conquer Split into independent parts, combine Usually no table Merge sort, quicksort partitions
Greedy One locally best choice per step Often O(1) extra Proof that greedy choice is safe (activity selection)
Dynamic Programming Try/recur on subproblems; reuse cached optima Table or memo map “Count ways”, “min/max over choices”, overlapping states

Quick Comparison Examples

Divide & Conquer Example:

Merge Sort: [5,2,4,6,1,3]
→ Split into [5,2,4] and [6,1,3]
→ Split further until single elements
→ Merge back (no overlapping subproblems)

Greedy Example:

Coin Change (US coins): 30 cents
→ Always take largest coin: 25 + 5 = 30 ✓
→ No need to try all combinations

DP Example:

Coin Change (any coins): 30 cents with [1,3,4]
→ Need to try combinations:
   4+4+4+4+4+4+4+2 = 8 coins
   4+4+4+4+4+3+3+3+1 = 9 coins
→ Must consider all possibilities

Memoization vs Tabulation

Top-Down (Memoization)

Write the natural recursive solution, then cache results in a hash map or array when a state is first computed.

Pros
  • Easy to start from the problem statement
  • Only computes needed states
  • Natural recursive thinking
Cons
  • Recursion overhead
  • Risk of stack overflow for large problems
  • Extra space for recursion stack

Example — Fibonacci:

def fib_memo(n, memo={}):
    if n <= 1:
        return n
    if n not in memo:
        memo[n] = fib_memo(n-1, memo) + fib_memo(n-2, memo)
    return memo[n]

Bottom-Up (Tabulation)

Fill a table iteratively from base cases upward, often controlling memory by keeping only the previous row or two.

Pros
  • No recursion overhead
  • Better space optimization possible
  • Avoids stack overflow
Cons
  • Must determine correct iteration order
  • May compute unnecessary states

Example — Fibonacci:

def fib_tab(n):
    if n <= 1:
        return n
    dp = [0] * (n + 1)
    dp[1] = 1
    for i in range(2, n + 1):
        dp[i] = dp[i-1] + dp[i-2]
    return dp[n]

Which One to Choose?

Factor Memoization Tabulation
Ease of implementationEasierHarder
SpaceUsually moreUsually less
TimeSometimes faster (only needed states)Consistent
Recursion depthRisk of stack overflowNo recursion
DebuggingHarder (recursion)Easier (iterative)
When to useQuick solution, small inputLarge input, optimal space

Both compute the same DP table in spirit; choose based on clarity, iteration order, and space constraints.

Where DP Shows Up

DP models optimization and counting over structured choices:

Classic DP Problems

1. Grid Problems

  • Unique paths
  • Minimum path sum
  • Dungeon game
  • Cherry pickup

2. Knapsack & Coin Problems

  • 0/1 Knapsack
  • Coin change (minimum coins)
  • Coin change (number of ways)
  • Partition equal subset sum

3. String Problems

  • Longest common subsequence
  • Edit distance
  • Word break
  • Palindrome partitioning
  • Wildcard matching

4. Sequence Problems

  • Longest increasing subsequence
  • Maximum subarray (Kadane's algorithm)
  • Decode ways

5. Stock Problems

  • Best time to buy/sell stock (I, II, III, IV)
  • With cooldown
  • With transaction fee

6. Miscellaneous

  • House robber (I, II, III)
  • Jump game
  • Interleaving strings
  • Distinct subsequences

Real-Life Applications

Dynamic programming is not only an interview topic—it is the backbone of optimization in science, engineering, and everyday software. The table below maps classic DP families to where they appear in the real world.

DP family Real-world use Example
Grid / pathsRobot navigation, warehouse picking, game mapsCount paths in a factory floor grid avoiding obstacles
Knapsack / subsetResource allocation, cargo loading, portfolio selectionMaximize value of packages that fit in a truck
Coin changePOS change-making, vending machines, fare systemsFewest coins to return $2.37 in change
String DPSpell check, plagiarism detection, DNA alignmentEdit distance between “kitten” and “sitting”
Sequence DPStock trading rules, trend analysis, signal processingBest buy/sell days with transaction limits
Interval DPMatrix chain multiplication, query optimizationOptimal order to multiply matrices in graphics pipelines
Tree DPNetwork routing on trees, org-chart decisionsMaximum independent set on a dependency tree
Game theoryChess engines, auction bidding, adversarial AIMinimax with memoized game states

Cross-Domain Examples

  • Bioinformatics: Align two DNA sequences to find similarity (edit distance / LCS variants)
  • Natural language processing: Word break for Chinese/Japanese; autocorrect via edit distance
  • Operations research: Scheduling jobs, assigning tasks under budgets (knapsack family)
  • Computer graphics: Seam carving and image segmentation use DP on grids
  • Economics: Multi-period investment and consumption (stock DP models)
  • Telecom: Error-correcting codes and Viterbi decoding in cell networks
Learn the pattern, not just the puzzle: Interview problems are simplified versions of these systems. Recognizing “this is knapsack” or “this is edit distance” lets you reuse the same state definition and complexity analysis you will see in later tutorials.

Key Takeaway

Dynamic programming = recurrence + overlapping subproblems + stored optimal sub-answers.

Steps to Solve DP Problems

  1. Identify DP properties — Check for optimal substructure and overlapping subproblems.
  2. Define state — What information is needed to make decisions? What parameters identify a subproblem?
  3. Define recurrence — How does the optimal solution depend on smaller subproblems?
  4. Define base cases — What are the simplest subproblems and their answers?
  5. Choose implementation — Top-down (memoization) or bottom-up (tabulation); consider time and space constraints.
  6. Optimize — Can we reduce space? Can we improve time complexity?
  7. Trace and verify — Test with small inputs; verify the recurrence works correctly.

Next Steps

Continue Learning

  1. Memoization vs Tabulation — Deep dive into both approaches with examples
  2. DP Properties & Complexity — Detailed analysis of optimal substructure and overlapping subproblems
  3. Fibonacci & Climbing Stairs — Beginner problems to apply DP

Practice Problems

Beginner Level:

Intermediate Level:

Interview Preparation

Summary

Concept Key Points
DefinitionOptimizing overlapping subproblems with stored results
PropertiesOptimal substructure + Overlapping subproblems
ApproachesTop-down (memoization) vs Bottom-up (tabulation)
VersusDP ≠ Greedy ≠ Divide-and-Conquer
ApplicationsCount ways, min/max, decision problems, string matching
GoalTime: Exponential → Polynomial; Space: Usually O(n) or O(n²)

Quick Reference Card

When to use DP:

  • ✓ Problem asks for “number of ways”
  • ✓ Problem asks for “minimum/maximum”
  • ✓ Problem has multiple overlapping subproblems
  • ✓ Recursive solution is exponential

When NOT to use DP:

  • ✗ No overlapping subproblems
  • ✗ Greedy works
  • ✗ Simple recursion without state repetition

Common Time Complexity Classes:

  • O(n) — 1D DP (Fibonacci, House Robber)
  • O(n²) — 2D DP (LCS, Edit Distance)
  • O(n × W) — Knapsack (W = capacity)
  • O(n × 2ⁿ) — Bitmask DP