Interval DP Fundamentals
Interval DP solves problems on subarrays/substrings by considering all possible split points within an interval.
General Pattern
// dp[i][j] = optimal value for interval [i, j]
// Base case: dp[i][i] = 0 or some initial value
// Transition: Try all split points k in [i, j]
for (int len = 2; len <= n; len++) { // interval length
for (int i = 0; i <= n - len; i++) { // start index
int j = i + len - 1; // end index
for (int k = i; k < j; k++) { // split point
dp[i][j] = optimize(dp[i][j], dp[i][k] + dp[k+1][j] + cost(i,k,j));
}
}
}
Matrix Chain Multiplication
Given matrices A1, A2, ..., An, find the minimum number of scalar multiplications needed to compute the product.
// p[] = dimensions, p[0] x p[1], p[1] x p[2], ..., p[n-1] x p[n]
// dp[i][j] = min cost to multiply matrices i to j
public int matrixChainOrder(int[] p) {
int n = p.length - 1; // number of matrices
int[][] dp = new int[n][n];
// Base case: cost to multiply single matrix = 0
// dp[i][i] = 0 (already initialized)
// Fill for chain lengths 2 to n
for (int len = 2; len <= n; len++) {
for (int i = 0; i <= n - len; i++) {
int j = i + len - 1;
dp[i][j] = Integer.MAX_VALUE;
for (int k = i; k < j; k++) {
// Cost = dp[i][k] + dp[k+1][j] + p[i]*p[k+1]*p[j+1]
int cost = dp[i][k] + dp[k + 1][j] + p[i] * p[k + 1] * p[j + 1];
dp[i][j] = Math.min(dp[i][j], cost);
}
}
}
return dp[0][n - 1];
}
Trace Example
p = [10, 30, 5, 60] → 3 matrices: 10x30, 30x5, 5x60
len=2: dp[0][1] = 10*30*5 = 1500
dp[1][2] = 30*5*60 = 9000
len=3: dp[0][2] = min(
dp[0][0] + dp[1][2] + 10*5*60 = 0 + 9000 + 3000 = 12000,
dp[0][1] + dp[2][2] + 10*30*60 = 1500 + 0 + 18000 = 19500
) = 12000
Answer: 12000 (multiply as (A1 x A2) x A3)
Minimum Score Triangulation
// Minimum score triangulation of polygon
public int minScoreTriangulation(int[] values) {
int n = values.length;
int[][] dp = new int[n][n];
for (int len = 2; len < n; len++) {
for (int i = 0; i < n - len; i++) {
int j = i + len;
dp[i][j] = Integer.MAX_VALUE;
for (int k = i + 1; k < j; k++) {
int cost = dp[i][k] + dp[k][j] + values[i] * values[k] * values[j];
dp[i][j] = Math.min(dp[i][j], cost);
}
}
}
return dp[0][n - 1];
}
Key Insights for Interval DP
- Order of computation: Length 2 first, then length 3, etc.
- Split point: Try all possible k to find optimal split
- Cost function: Depends on the specific problem
- Base case: Single element intervals have 0 cost
Palindrome Problems with Interval DP
Palindrome Partitioning II
Minimum cuts needed to partition a string such that every substring is a palindrome.
// dp[i] = minimum cuts for s[0..i]
public int minCut(String s) {
int n = s.length();
boolean[][] isPalin = new boolean[n][n];
int[] dp = new int[n];
// Precompute palindrome table
for (int len = 1; len <= n; len++) {
for (int i = 0; i <= n - len; i++) {
int j = i + len - 1;
if (s.charAt(i) == s.charAt(j)) {
if (len <= 3 || isPalin[i + 1][j - 1]) {
isPalin[i][j] = true;
}
}
}
}
// Compute minimum cuts
for (int i = 0; i < n; i++) {
if (isPalin[0][i]) {
dp[i] = 0; // No cut needed if whole prefix is palindrome
} else {
dp[i] = i; // Maximum cuts (cut at every position)
for (int j = 0; j < i; j++) {
if (isPalin[j + 1][i]) {
dp[i] = Math.min(dp[i], dp[j] + 1);
}
}
}
}
return dp[n - 1];
}
Longest Palindromic Substring
// dp[i][j] = true if s[i..j] is palindrome
public String longestPalindrome(String s) {
int n = s.length();
boolean[][] dp = new boolean[n][n];
int start = 0, maxLen = 1;
// Base case: single character
for (int i = 0; i < n; i++) dp[i][i] = true;
// Check for length 2
for (int i = 0; i < n - 1; i++) {
if (s.charAt(i) == s.charAt(i + 1)) {
dp[i][i + 1] = true;
start = i;
maxLen = 2;
}
}
// Check for length 3 and above
for (int len = 3; len <= n; len++) {
for (int i = 0; i <= n - len; i++) {
int j = i + len - 1;
if (s.charAt(i) == s.charAt(j) && dp[i + 1][j - 1]) {
dp[i][j] = true;
if (len > maxLen) {
start = i;
maxLen = len;
}
}
}
}
return s.substring(start, start + maxLen);
}
Burst Balloons
// Maximum coins from bursting balloons
// Coins = nums[left] * nums[i] * nums[right] for burst balloon i
public int maxCoins(int[] nums) {
int n = nums.length;
int[] newNums = new int[n + 2];
newNums[0] = 1;
newNums[n + 1] = 1;
for (int i = 0; i < n; i++) newNums[i + 1] = nums[i];
int[][] dp = new int[n + 2][n + 2];
// Fill for all interval lengths
for (int len = 1; len <= n; len++) {
for (int left = 1; left <= n - len + 1; left++) {
int right = left + len - 1;
for (int k = left; k <= right; k++) {
int coins = newNums[left - 1] * newNums[k] * newNums[right + 1]
+ dp[left][k - 1] + dp[k + 1][right];
dp[left][right] = Math.max(dp[left][right], coins);
}
}
}
return dp[1][n];
}
Interval DP Pattern Summary
| Problem | dp[i][j] | Transition |
|---|---|---|
| Matrix Chain | Min cost for matrices i..j | min(dp[i][k] + dp[k+1][j] + cost) |
| Burst Balloons | Max coins for balloons i..j | max(dp[left][k-1] + dp[k+1][right] + cost) |
| Palindrome Partition | Min cuts for s[0..i] | min(dp[j] + 1) if s[j+1..i] is palindrome |
| Longest Palindrome | Is s[i..j] palindrome? | s[i]==s[j] && dp[i+1][j-1] |
Practice Problems
You are given n balloons, indexed from 0 to n - 1. Each balloon has a number on it represented by an array nums. You are asked to burst all the balloons. If you burst the ith balloon, you will get nums[i - 1] * nums[i] * nums[i + 1] coins. If i - 1 or i + 1 goes out of bounds of the array, then treat it as if there is a balloon with a 1 on it. Return the maximum coins you can collect by bursting the balloons wisely.
Example:
Input: nums = [3,1,5,8]
Output: 167
One optimal order: burst 1 (3*1*5=15), then 5 (3*5*8=120), then 8 (3*8*1=24), then 3 (1*3*1=3). Total = 15+120+24+3 = 167. Actually 167 comes from: burst 1→5→3→8 = 15+15+45+120=195? Let me recalculate. Optimal: burst 1 (15), then 5 (3*5*8=120), then 8 (3*8*1=24), then 3 (1*3*1=3) = 162? Actually the answer is 167 from bursting in order: 1,5,3,8.
Optimal Solution — O(n^3) time, O(n^2) space
Interval DP. Think of bursting the last balloon k in interval [left, right]. Then dp[left][right] = max over all k of (dp[left][k-1] + dp[k+1][right] + nums[left-1]*nums[k]*nums[right+1]).
class Solution {
public int maxCoins(int[] nums) {
int n = nums.length;
int[] newNums = new int[n + 2];
newNums[0] = 1;
newNums[n + 1] = 1;
for (int i = 0; i < n; i++) newNums[i + 1] = nums[i];
int[][] dp = new int[n + 2][n + 2];
for (int len = 1; len <= n; len++) {
for (int left = 1; left <= n - len + 1; left++) {
int right = left + len - 1;
for (int k = left; k <= right; k++) {
int coins = newNums[left - 1] * newNums[k] * newNums[right + 1]
+ dp[left][k - 1] + dp[k + 1][right];
dp[left][right] = Math.max(dp[left][right], coins);
}
}
}
return dp[1][n];
}
}Edge Cases:
- Single balloon: return its value
- Two balloons: burst in any order
- All zeros: return 0
- All ones: minimal coins
Quiz
1. In Interval DP, what is the order of computation?
2. What is the time complexity of Interval DP problems?
3. What is the primary purpose of Interval Dynamic Programming?
4. What is a common mistake when implementing Interval Dynamic Programming?
Flashcards
Question
What is the general pattern for Interval DP?
Click to reveal answer
Answer
Process intervals by increasing length. For each interval [i,j], try all split points k. dp[i][j] = optimize(dp[i][k] + dp[k+1][j] + cost(i,k,j)).
Question
How does Burst Balloons differ from Matrix Chain Multiplication?
Click to reveal answer
Answer
In Burst Balloons, the split point k is the LAST balloon burst, and cost depends on neighbors (left-1, k, right+1). In Matrix Chain, cost depends on dimensions at split.
Question
What is Interval Dynamic Programming?
Click to reveal answer
Answer
Interval Dynamic Programming is a key concept in software engineering.
Question
When to use Interval Dynamic Programming?
Click to reveal answer
Answer
Use Interval Dynamic Programming when building production systems that require reliability, scalability, and maintainability.
Question
Interval Dynamic Programming best practices
Click to reveal answer
Answer
Follow SOLID principles, write clean code, test thoroughly, document decisions, and monitor in production.
Revision Notes
Key Takeaways
- 1.Interval DP: O(n^3) by trying all split points in each interval
- 2.Process intervals by increasing length
- 3.dp[i][j] represents optimal value for interval [i, j]
- 4.Cost function depends on the split point and problem specifics
Interview Tips
- •Draw out small examples to understand interval structure
- •Clarify if you're bursting last or first at split point
- •Explain the order of computation (length 2, 3, ...)
- •Discuss how to reconstruct the actual solution
Cheat Sheet
Interval DP Cheat Sheet
General Pattern:
for (int len = 2; len <= n; len++) {
for (int i = 0; i <= n - len; i++) {
int j = i + len - 1;
for (int k = i; k < j; k++) {
dp[i][j] = optimize(dp[i][j], dp[i][k] + dp[k+1][j] + cost);
}
}
}
Key Problems:
- Matrix Chain: min cost, cost = p[i]*p[k+1]*p[j+1]
- Burst Balloons: max coins, cost = nums[left-1]*nums[k]*nums[right+1]
- Palindrome Partition: min cuts, check if substring is palindrome
Time Complexity: O(n^3) - O(n^2) intervals × O(n) split points
Space Complexity: O(n^2) for dp table
Important: Process intervals by increasing length to ensure subintervals are solved first.