๐ŸŽ›๏ธ The Most Important DP Skill

Beginners struggle with DP not because the math is hard, but because they don't know what to put in dp[]. This module teaches you to derive the state definition from first principles โ€” every time.

The 3 Questions to Find Your State
What changes between recursive calls?
The parameters that change = your state dimensions.
House Robber: only i (current index) changes โ†’ 1D state dp[i]
LCS: both i and j (positions in two strings) change โ†’ 2D state dp[i][j]
Stocks with k transactions: day, k, holding โ†’ 3D state dp[day][k][holding]
What affects future decisions?
Only include in state what is necessary to make the optimal decision going forward.
Knapsack: need remaining_capacity because it limits future choices.
House Robber: do NOT need "how I got here" โ€” only current index matters.
Stock cooldown: need holding flag because you can't buy if you already hold.
What does dp[state] represent?
Write it in English. This IS your recurrence.
dp[i] = max money robbing from house i to end
dp[i][w] = max value using first i items with capacity w
dp[i][j] = LCS length of s1[0..i] and s2[0..j]
State Dimension Reference
StateWhen to useExamplesSpace
dp[i]Single sequence, one changing paramFibonacci, House Robber, LISO(n)
dp[i][j]Two sequences OR index + constraintLCS, Edit Distance, KnapsackO(nยฒ)
dp[i][j][k]Three constraints (often reducible)Stocks with k txns, 3D GridO(nยณ)
dp[row][col]2D grid movementUnique Paths, Min Path SumO(mยทn)
dp[day][hold]State machine at each stepStock Buy/Sell with cooldownO(n)
dp[mask]Subset of items visited (nโ‰ค20)TSP, Bitmask DPO(2โฟ)
dp[i][j] intervalSubarray/substring of length j-iMCM, Burst BalloonsO(nยฒ)
dp[node]Tree โ€” depends on subtree resultsHouse Robber III, DiameterO(n)
Worked Examples โ€” Deriving State from Scratch
Coin Change โ€” LC 322
Problem: min coins to make amount

Q1: What changes? โ†’ remaining amount (after picking a coin)
Q2: What affects future? โ†’ only rem matters โ€” once I choose a coin, the remaining amount fully determines future options
Q3: dp[rem] = min coins to make exactly rem

// State: dp[rem] = min coins to make amount rem
int[] dp = new int[amount+1];
Arrays.fill(dp, amount+1);  // "infinity"
dp[0] = 0;                  // base: 0 coins to make 0

for (int rem = 1; rem <= amount; rem++)
    for (int coin : coins)
        if (coin <= rem)
            dp[rem] = Math.min(dp[rem], dp[rem-coin] + 1);
// Recurrence: dp[rem] = min over all coins of (dp[rem-coin] + 1)
// "Use 1 coin + solve smaller subproblem"
State Reduction โ€” From 3D to 1D
๐Ÿ’ก Always try to reduce dimensions

If dp[i] only depends on dp[i-1] โ†’ use two variables. If dp[i][j] only depends on row i-1 โ†’ use 1D rolling array. This is what separates good solutions from great ones.

OriginalReducedTrick
dp[n] Fibonaccia, b โ€” O(1)Only need prev 2 values
dp[n][W] Knapsackdp[W] โ€” O(W)Iterate weights in reverse
dp[m][n] LCSdp[n] with prev var โ€” O(n)Row i only needs row i-1; save diagonal in prev
dp[n][k][2] Stocksbuy, sell arrays โ€” O(k)At each day only 2 states per transaction count