Skip to main content

DSAPath17 mincore

Dynamic Programming

Dynamic programming solves problems by storing overlapping subproblem results. It works when the problem has reusable subproblems and a state definition with a valid recurrence.

Why This Matters

Dynamic programming turns repeated recursive work into stored subproblem answers. It appears in edit distance, knapsack, sequence alignment, parsing, shortest paths, planning, and value iteration.

The skill is not memorizing a list of famous problems. The skill is designing the state and recurrence.

Learning Objectives

By the end, you should be able to:

  • Identify overlapping subproblems and optimal substructure.
  • Define a DP state, base cases, recurrence, and fill order.
  • Compare memoization, tabulation, and space-optimized DP.
  • Explain why memoization changes repeated recursion into a bounded set of stored states.
  • Recognize when greedy, divide-and-conquer, or plain search is a better fit than DP.

Core Idea

Use DP when a problem has overlapping subproblems and a recurrence that combines smaller answers into larger answers.

StyleDirectionStrengthRisk
Memoizationtop-down recursionclose to natural recurrencerecursion overhead, cache keys
Tabulationbottom-up iterationexplicit order, often fastertable design can be awkward
Space-optimized DPkeep only needed rows/stateslower memoryeasier to corrupt dependencies
Greedychoose local best oncesimpler when validfails without exchange property

Non-Example or Failure Mode

Binary search is not dynamic programming. It has a shrinking search interval, but it does not solve overlapping subproblems whose answers should be stored and reused.

The common failure mode is using DP as a label for any recursive solution. If subproblems do not repeat, memoization adds memory and complexity without reducing the asymptotic work.

Worked Example

Fibonacci is the smallest DP example because naive recursion recomputes the same states.

function fib(n: number, memo = new Map<number, number>()): number {
  if (n <= 1) return n;
  if (memo.has(n)) return memo.get(n)!;
  const value = fib(n - 1, memo) + fib(n - 2, memo);
  memo.set(n, value);
  return value;
}

The state is n. The recurrence is fib(n) = fib(n - 1) + fib(n - 2). Memoization changes exponential repeated recursion into O(n) stored states.

For edit distance, the state becomes (i, j): the answer for prefixes a[0..i) and b[0..j).

Builder Connections

  • Text systems use edit distance and sequence alignment ideas.
  • Reinforcement learning uses dynamic programming in value iteration.
  • Parsers use DP for chart parsing.
  • Route planning uses shortest-path recurrences.
  • Systems code uses DP-like caching whenever repeated subproblems are expensive and inputs are stable.

Common Mistakes

MistakeCorrection
Starting with code before defining the state.Name the state, base cases, recurrence, and fill order before implementation.
Using DP without overlapping subproblems.Memoization only helps when the same subproblem can occur multiple times.
Forgetting base cases.Base cases anchor the recurrence and prevent undefined table reads.
Storing too much state.Keep only variables needed to determine future transitions.
Updating in the wrong order.Space optimization must preserve dependencies that later states still need.

Diagnostic Questions

Question typeQuestionAnswer signal
DefinitionWhat is the state?The minimal information that identifies a subproblem, such as n or (i, j).
Example / non-exampleDoes binary search need DP?No. Its subproblems do not overlap; it discards half the search space.
ComputationHow many states are in an edit-distance table for lengths m and n?(m + 1)(n + 1) states including empty-prefix base cases.
ProofWhy does memoized Fibonacci compute each state once?After fib(k) is stored, future calls return from the memo table instead of recursing.
TransferHow is value iteration a DP idea?It repeatedly updates value estimates from successor states using a Bellman recurrence.

Exercises

Beginner:

  • Identify the DP state for Fibonacci.
  • Fill a 3 by 3 edit-distance table.
  • Write base cases for climbing stairs with one-step or two-step moves.

Intermediate:

  • Derive the recurrence for 0/1 knapsack.
  • Convert memoized Fibonacci into tabulation.

Challenge:

  • Implement value iteration on a tiny gridworld and explain the state transition.

Diagram Recommendation

Type: subproblem grid.

Caption: "Edit distance table filled from base cases toward the final answer."

Purpose: Show that DP is dependency order over states, not a magic code pattern.

Implementation Task

Implement edit distance with a two-dimensional table.

function editDistance(a: string, b: string) {
  const dp = Array.from({ length: a.length + 1 }, () =>
    Array(b.length + 1).fill(0),
  );
  for (let i = 0; i <= a.length; i += 1) dp[i]![0] = i;
  for (let j = 0; j <= b.length; j += 1) dp[0]![j] = j;
  for (let i = 1; i <= a.length; i += 1) {
    for (let j = 1; j <= b.length; j += 1) {
      const cost = a[i - 1] === b[j - 1] ? 0 : 1;
      dp[i]![j] = Math.min(
        dp[i - 1]![j]! + 1,
        dp[i]![j - 1]! + 1,
        dp[i - 1]![j - 1]! + cost,
      );
    }
  }
  return dp[a.length]![b.length]!;
}

Then reduce memory to two rows and explain which dependencies survive.

Next Topics

References

  • Cormen, Leiserson, Rivest, Stein. Introduction to Algorithms (4th ed., 2022). Ch. 14.
  • MIT OpenCourseWare. 6.006 Introduction to Algorithms, Spring 2020.
  • MIT OpenCourseWare. 6.046J Design and Analysis of Algorithms, Spring 2015.
  • Kleinberg and Tardos. Algorithm Design (2005). Ch. 6.