Chapter 5: Interval DP

Some dynamic programming problems are not indexed by a single position or a grid cell — they are indexed by a range. The subproblem is “what is the optimal answer for the contiguous segment from index i to index j?” Written as dp[i][j], this pattern appears whenever you must decide how to split or merge a sequence.

Classic triggers include matrix parenthesization, bursting balloons, palindrome partitioning, and optimal binary search trees. The unifying question is: where do I cut this interval? You try every split point k between i and j, combine optimal answers from the left piece [i, k] and right piece [k+1, j], and take the best.

Pattern recognition: If the problem asks about an optimal way to split or merge a sequence — parenthesize, partition, burst, cut — it is likely interval DP. The state is almost always a range [i, j].

Matrix Chain Multiplication

Given a chain of matrices A₀, A₁, …, Aₙ₋₁ where matrix Aᵢ has dimensions dims[i] × dims[i+1], find the minimum number of scalar multiplications needed to compute the product. The order of multiplication matters enormously: for three matrices, (AB)C and A(BC) can have vastly different costs.

Define dp[i][j] as the minimum cost to multiply matrices i through j. The base case is dp[i][i] = 0 — a single matrix needs no work. For longer intervals, try every split k:

dp[i][j] = min over k in [i, j-1] of:
    dp[i][k] + dp[k+1][j] + dims[i] * dims[k+1] * dims[j+1]

The last term is the cost of multiplying the two resulting matrices.

What does dp[i][j] represent in Matrix Chain Multiplication?

Diagonal Fill Order

Interval DP has a fill order unlike anything you have seen so far. You cannot fill row-by-row or left-to-right — you must fill by interval length, starting with length 1 (the diagonal), then length 2, then 3, and so on. When computing dp[i][j], every sub-interval dp[i][k] and dp[k+1][j] must already be filled, which means all shorter intervals must come first.

Fill order for n=4 matrices (indices 0..3):

Length 1:  dp[0][0] dp[1][1] dp[2][2] dp[3][3]   ← diagonal
Length 2:  dp[0][1] dp[1][2] dp[2][3]             ← one above diagonal
Length 3:  dp[0][2] dp[1][3]
Length 4:  dp[0][3]                               ← answer cell

This diagonal sweep is the signature of interval DP.
M0
M1
M2
M3
M4
M5
M0
0
M1
0
M2
0
M3
0
M4
0
M5
0

dp[0][1] = min over k of (dp[0][k] + dp[k+1][1] + d0·d(k+1)·d2) → best at k=0: 0 + 0 + 30×35×15 = 15750

Step 1 / 15
Loading...

Burst Balloons

LeetCode 312: You have balloons with values nums[i]. Bursting balloon i gives coins equal to nums[i-1] × nums[i] × nums[i+1] (with boundary balloons of value 1). Burst all balloons to maximize total coins.

The forward-thinking approach fails — the order of bursting changes which neighbors exist. The breakthrough is reverse thinking: instead of asking “which balloon do I burst first?”, ask “which balloon do I burst last?” If balloon k is the last one burst in range [i, j], then at that moment its neighbors are fixed: nums[i-1] and nums[j+1] (using padded boundaries). The subproblems on the left and right become independent.

Pad with 1 at both ends: [1, nums[0], nums[1], ..., nums[n-1], 1]

dp[i][j] = max coins from bursting all balloons in original range i..j

For each k in [i, j] as the LAST balloon burst:
  coins = dp[i][k-1] + dp[k+1][j] + padded[i] * padded[k+1] * padded[j+2]

(In code with 0-indexed padded array, k is the last burst index in the open interval.)

Notice the same interval structure and diagonal fill order as matrix chain. The difference is the interpretation of k: split point for multiplication versus last-burst balloon for coins.

b0=3
b1=1
b2=5
b3=8
b0=3
3
b1=1
15
b2=5
40
b3=8
40

dp[0][1]: burst 0 last → 30

Step 1 / 6
Loading...

Interval DP fills diagonally — small intervals first, building up to the full range dp[0][n-1]. Whether you are splitting a matrix chain or choosing the last balloon to burst, the table shape and fill order are identical. Master the diagonal sweep once and it applies everywhere in this pattern.

Summary

  • State: dp[i][j] = optimal answer for range [i, j]
  • Transition: try every split/last-choice k in the range
  • Fill order: by interval length (diagonal sweep)
  • Answer: dp[0][n-1]
  • Time: O(n³) for a sequence of length n

Off-by-one errors are common in interval DP. Be precise about whether j is inclusive, whether you pad the array, and whether k represents a split between matrices or a balloon index. Draw a small example before coding.