Dynamic Programming

2 min read Last updated Sat Jun 27 2026 08:46:52 GMT+0000 (Coordinated Universal Time)

Dynamic programming solves problems by breaking them into overlapping subproblems, solving each once, and caching the result.

Elements

A problem suits DP iff:

  • Optimal substructure
    An optimal solution to the problem contains optimal solutions to its subproblems.
  • Overlapping subproblems
    The same subproblems recur across different recursive branches.

DP vs Divide-and-Conquer

Both decompose a problem recursively.

  • Divide-and-conquer
    Subproblems are independent. Results are not reused.
  • Dynamic programming
    Subproblems overlap. Results are cached and reused.

Approaches

  • Memoization (top-down)
    Solve recursively. Cache each result on first computation and return it directly on repeat calls.
  • Tabulation (bottom-up)
    Fill a table from base cases upward in dependency order. No recursion stack.

Requirements

  • Problem must be expressible as a recurrence.
  • Number of distinct subproblem instances must be polynomially bounded.
  • Subproblem dependency graph must be a DAG (no cycles).

Fibonacci Example

F(n)=F(n1)+F(n2),F(0)=0,  F(1)=1F(n) = F(n-1) + F(n-2), \quad F(0) = 0,\; F(1) = 1

Naive recursion recomputes F(k)F(k) at every branch: time O(2n)O(2^n).

Tabulation:

  1. Set dp[0]=0dp[0] = 0, dp[1]=1dp[1] = 1.
  2. For i=2i = 2 to nn: dp[i]=dp[i1]+dp[i2]dp[i] = dp[i-1] + dp[i-2].
  3. Return dp[n]dp[n].

Time: O(n)O(n). Space: O(n)O(n), reducible to O(1)O(1) by keeping only the last 2 values.

Was this helpful?