v9.1.1
Menu

Chapter 11: Dynamic Programming Advanced

Week 11

Tackle advanced DP problems involving two sequences, item selection, and subset partitioning. Master LCS, edit distance, LIS, knapsack variants, and partition problems that form the backbone of competitive programming and technical interviews.

Topics
6
Demos
3
Videos
3
Min read
30

Chapter Overview

Building on the DP fundamentals from the previous chapter, we now tackle problems that require more sophisticated state definitions and recurrences. These problems typically involve two-dimensional DP tables, multi-choice decisions at each step, and clever reductions from one problem to another.

The key themes in advanced DP are:

  • Dual-sequence DP: Problems like LCS and edit distance operate on two strings or sequences simultaneously, requiring a 2D table indexed by positions in both sequences
  • Item selection DP: Knapsack problems involve choosing from a set of items subject to a constraint, with each item either included or excluded (0/1) or used unlimited times (unbounded)
  • Subsequence DP: LIS requires finding optimal subsequences within a single sequence, with an elegant O(n log n) optimization using binary search
  • Reduction to known problems: Many problems (like partition equal subset sum) can be reformulated as variants of simpler known problems (subset sum, which is itself a knapsack variant)

This chapter covers:

  • Longest Common Subsequence: 2D DP on two sequences with subsequence matching
  • Edit Distance: Minimum operations to transform one string into another
  • Longest Increasing Subsequence: Classic 1D subsequence problem with an O(n log n) optimization
  • 0/1 Knapsack: The foundational item selection problem
  • Unbounded Knapsack & Coin Change: Variants with unlimited item usage
  • Partition Equal Subset Sum: Reducing a partition problem to subset sum DP

Chapter Roadmap

Click any topic to jump in

Explainer videoInteractive demo
1
Longest Common Subsequence

$O(mn)$ 2D DP on two strings with reconstruction via backward walk.

2D Table ConstructionReconstructing the LCS
2
Edit Distance

Insert, delete, replace as three transitions; $dp[i][j] = 1 + \min(\cdot)$.

Three Operations as TransitionsVisualizing the DP Table
Builds on previous
3
Longest Increasing Subsequence

$O(n^2)$ DP vs. the patience-sort $O(n \log n)$ tails array.

O(n^2) DP ApproachO(n log n) with Binary Search
Multiple approaches

Each tackles a different aspect

4
0/1 Knapsack

Binary include/exclude with $O(nW)$ DP and 1D $O(W)$ space via reverse iteration.

Include or Exclude DecisionSpace Optimization with 1D Array
5
Unbounded Knapsack & Coin Change

Forward iteration allows item reuse — and solves minimum coin change.

Unbounded vs 0/1 KnapsackCoin Change: Minimum Coins
Builds on previous
6
Partition Equal Subset Sum

Reduction to subset sum $S/2$ with 1D boolean DP and bitset speedup.

Reduction to Subset SumOptimization and Early Termination

Topics

6 topics in this chapter

When you run a diff on two versions of a file, the tool must decide which lines stayed the same and which were added or removed. Matching lines greedily, pairing each line with the first equal line in the other file, can lock in an early match that blocks many later ones. The real question is: what is the longest sequence of lines that appears in both files, in the same order, with gaps allowed? That is the longest common subsequence, and it also underlies DNA comparison and plagiarism checks.

The previous chapter ended with Maximal Square, where each cell of a 2D table described a region of one grid. This chapter keeps the 2D table but changes what the axes mean: rows index a prefix of the first sequence and columns index a prefix of the second. Each cell compares only the last characters of the two prefixes, and the answer grows one character at a time.

We first build the table and its recurrence on a small pair of strings. Then we walk back through the finished table to recover an actual common subsequence, not just its length.

Definition

Given sequences AA of length mm and BB of length nn, a common subsequence is a sequence obtainable from both by deleting elements without reordering. The LCS problem asks for the longest one. With dp[i][j]dp[i][j] the LCS length of A[0..i)A[0..i) and B[0..j)B[0..j), it is solved in O(mn)O(mn) time, and one LCS is recovered in O(m+n)O(m + n) extra time.

In this topic

  1. 12D Table Construction
  2. 2Reconstructing the LCS
1 of 2
2D Table Construction

Trying every subsequence of one string costs 2m2^m checks, so we need a state that reuses work. Let dp[i][j]dp[i][j] be the LCS length of the first ii characters of AA and the first jj characters of BB. An empty prefix shares nothing, so row 0 and column 0 are zero. If the last characters match, A[i−1]=B[j−1]A[i-1] = B[j-1], some LCS ends with that pair, giving dp[i−1][j−1]+1dp[i-1][j-1] + 1. If not, at least one of the two characters is unused, so drop either and keep the better result: max⁡(dp[i−1][j],dp[i][j−1])\max(dp[i-1][j], dp[i][j-1]). Row-major filling satisfies every dependency, as in the grid DP of the last chapter.

Mathematical Intuition

Define dp[i][j]dp[i][j] = length of LCS of prefixes A[0..i)A[0..i) and B[0..j)B[0..j). Recurrence: dp[i][j]=dp[i−1][j−1]+1dp[i][j] = dp[i-1][j-1] + 1 if A[i−1]=B[j−1]A[i-1]=B[j-1], else max⁡(dp[i−1][j],dp[i][j−1])\max(dp[i-1][j], dp[i][j-1]). Time O(mn)O(mn), space O(mn)O(mn) reducible to O(min⁡(m,n))O(\min(m,n)). Correctness: any LCS either ends with the matching pair (use diagonal) or skips a character from one string (use one of the two neighbors).

Example:

Find the LCS of 'ABCBDAB' and 'BDCAB'.

2 of 2
Reconstructing the LCS

The table stores lengths, but a diff tool needs the matched characters themselves. Start at dp[m][n]dp[m][n] and retrace the decision that produced each value. If A[i−1]=B[j−1]A[i-1] = B[j-1], that pair belongs to an LCS: record it and step diagonally to (i−1,j−1)(i-1, j-1). Otherwise step to whichever neighbour, dp[i−1][j]dp[i-1][j] or dp[i][j−1]dp[i][j-1], holds the larger value, since that is where the length came from. Stop at row 0 or column 0 and reverse the recorded characters. The walk takes O(m+n)O(m + n) steps and needs no extra pointers. When the two neighbours tie, either choice is valid, which is why one pair of strings can have several different LCSs.

Mathematical Intuition

After filling the DP table, walk backward from dp[m][n]dp[m][n]: if A[i−1]=B[j−1]A[i-1]=B[j-1], append that character and move to (i−1,j−1)(i-1, j-1); otherwise move to whichever of (i−1,j)(i-1, j) or (i,j−1)(i, j-1) has the larger value. This reconstructs one LCS in O(m+n)O(m+n) time after the O(mn)O(mn) DP. Storing parent pointers is optional since the DP values themselves encode the path.

Example:

Given the DP table for 'ACE' and 'ABCDE', trace back to find the LCS.