Skip to main content

๐Ÿง  Dynamic Programming

One-line summary: Break a problem into overlapping subproblems, solve each once โ€” turning exponential time into polynomial.


Diagramโ€‹

Dynamic Programming GIF

๐ŸŽฏ Conceptโ€‹

Dynamic Programming (DP) solves complex problems by breaking them into simpler subproblems, solving each subproblem once, and storing (caching) the result. Apply DP when a problem has both:

  1. Optimal substructure: the optimal solution is built from optimal solutions of its subproblems.
  2. Overlapping subproblems: the same subproblem is computed many times by a naive recursion.
flowchart TD
A["Naive recursion\nexponential, recomputes"] --> B{"Overlapping\nsubproblems?"}
B -->|Yes| C["Add caching"]
C --> D["Top-Down\n(Memoization)\nrecursion + cache"]
C --> E["Bottom-Up\n(Tabulation)\niterative table"]
D --> F["Polynomial time"]
E --> F

Top-Down vs Bottom-Upโ€‹

AspectTop-Down (Memoization)Bottom-Up (Tabulation)
StyleRecursion + cacheIterative table filling
OrderSolves on demandSolves all states in order
SpaceO(states) + call stackO(states), often space-optimizable
IntuitionEasier to write from recurrenceFaster, no recursion overhead

Common DP Categoriesโ€‹

1D DP ยท 2D / grid DP ยท Knapsack (take / not-take) ยท LIS ยท LCS / DP on strings ยท DP on stocks ยท Partition / interval DP ยท Bitmask DP.


โšก Time & Space Complexityโ€‹

PatternTimeSpace
1D DP (house robber, climb stairs)O(n)O(1) optimised
2D DP (grid / string)O(mยทn)O(n) row-optimised
0/1 KnapsackO(nยทW)O(W)
LIS (DP)O(nยฒ)O(n)
LIS (patience/binary search)O(n log n)O(n)
LCSO(mยทn)O(mยทn)

Key Insight: The number of distinct states ร— work per state = total time. Optimize space by keeping only the states you still need (e.g., last row/two variables).


Common Patternsโ€‹

1D DP โ€” House Robberโ€‹

function rob(nums) {
let prev2 = 0,
prev1 = 0;
for (const n of nums) {
const curr = Math.max(prev1, prev2 + n);
prev2 = prev1;
prev1 = curr;
}
return prev1;
}
// State: best loot up to house i. Time O(n), Space O(1).

2D DP โ€” Edit Distance (Levenshtein)โ€‹

function editDistance(w1, w2) {
const m = w1.length,
n = w2.length;
const dp = Array.from({ length: m + 1 }, (_, i) =>
Array.from({ length: n + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0)),
);
for (let i = 1; i <= m; i++)
for (let j = 1; j <= n; j++)
dp[i][j] =
w1[i - 1] === w2[j - 1]
? dp[i - 1][j - 1]
: 1 + Math.min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]);
return dp[m][n];
}
// Time O(m*n), Space O(m*n).

0/1 Knapsack โ€” take / not-takeโ€‹

function knapsack(weights, values, W) {
const dp = new Array(W + 1).fill(0);
for (let i = 0; i < weights.length; i++)
for (let w = W; w >= weights[i]; w--)
// iterate backwards for 0/1
dp[w] = Math.max(dp[w], dp[w - weights[i]] + values[i]);
return dp[W];
}
// Time O(n*W), Space O(W).

LIS โ€” Longest Increasing Subsequence O(n log n)โ€‹

function lengthOfLIS(nums) {
const tails = [];
for (const x of nums) {
let lo = 0,
hi = tails.length;
while (lo < hi) {
const mid = (lo + hi) >> 1;
if (tails[mid] < x) lo = mid + 1;
else hi = mid;
}
tails[lo] = x;
}
return tails.length;
}
// Binary search keeps the smallest tail per length. Time O(n log n).

๐Ÿงช Worked Example: Coin Change (min coins)โ€‹

Given coin denominations and an amount, find the fewest coins to make it.

function coinChange(coins, amount) {
const dp = new Array(amount + 1).fill(Infinity);
dp[0] = 0; // 0 coins to make amount 0
for (let a = 1; a <= amount; a++) {
for (const coin of coins) {
if (coin <= a) dp[a] = Math.min(dp[a], dp[a - coin] + 1);
}
}
return dp[amount] === Infinity ? -1 : dp[amount];
}
// dp[a] = fewest coins to form amount a. Time O(amount * coins), Space O(amount).

Recurrence: dp[a] = min(dp[a - coin] + 1) over all coins that fit โ€” optimal substructure (best for a uses the best for a - coin) and overlapping subproblems (dp[a - coin] reused).


Pitfallsโ€‹

  • Wrong iteration order: 0/1 knapsack must iterate capacity backwards; unbounded knapsack forwards.
  • Uninitialized base cases: forgetting dp[0] leads to wrong answers.
  • Not space-optimizing: many 2D DPs only need the previous row.
  • Confusing subsequence vs substring: contiguity changes the recurrence.

Practice Problemsโ€‹

ProblemDifficultySolution
LC 70 โ€” Climbing StairsEasy
LC 121 โ€” Best Time to Buy and Sell StockEasy
LC 198 โ€” House RobberMedium
LC 322 โ€” Coin ChangeMedium
LC 300 โ€” Longest Increasing SubsequenceMedium
LC 1143 โ€” Longest Common SubsequenceMedium

| LC 62 โ€” Unique Paths | Medium | | | LC 63 โ€” Unique Paths II | Medium | | | LC 64 โ€” Minimum Path Sum | Medium | | | LC 91 โ€” Decode Ways | Medium | | | LC 96 โ€” Unique Binary Search Trees | Medium | | | LC 120 โ€” Triangle | Medium | | | LC 139 โ€” Word Break | Medium | | | LC 152 โ€” Maximum Product Subarray | Medium | | | LC 213 โ€” House Robber II | Medium | | | LC 221 โ€” Maximal Square | Medium | | | LC 279 โ€” Perfect Squares | Medium | | | LC 300 โ€” Longest Increasing Subsequence | Medium | | | LC 309 โ€” Best Time to Buy and Sell Stock with Cooldown | Medium | | | LC 322 โ€” Coin Change | Medium | | | LC 338 โ€” Counting Bits | Medium | | | LC 343 โ€” Integer Break | Medium | | | LC 377 โ€” Combination Sum IV | Medium | | | LC 416 โ€” Partition Equal Subset Sum | Medium | | | LC 494 โ€” Target Sum | Medium | | | LC 516 โ€” Longest Palindromic Subsequence | Medium | | | LC 518 โ€” Coin Change 2 | Medium | |

| LC 740 โ€” Delete and Earn | Medium | | | LC 931 โ€” Minimum Falling Path Sum | Medium | |

| LC 42 โ€” Trapping Rain Water | Hard | | | LC 44 โ€” Wildcard Matching | Hard | | | LC 72 โ€” Edit Distance | Hard | | | LC 85 โ€” Maximal Rectangle | Hard | | | LC 87 โ€” Scramble String | Hard | | | LC 115 โ€” Distinct Subsequences | Hard | | | LC 123 โ€” Best Time to Buy and Sell Stock III | Hard | | | LC 132 โ€” Palindrome Partitioning II | Hard | | | LC 140 โ€” Word Break II | Hard | | | LC 188 โ€” Best Time to Buy and Sell Stock IV | Hard | | | LC 312 โ€” Burst Balloons | Hard | | | LC 329 โ€” Longest Increasing Path in a Matrix | Hard | | | LC 354 โ€” Russian Doll Envelopes | Hard | | | LC 410 โ€” Split Array Largest Sum | Hard | | | LC 446 โ€” Arithmetic Slices II - Subsequence | Hard | | | LC 472 โ€” Concatenated Words | Hard | | | LC 546 โ€” Remove Boxes | Hard | | | LC 664 โ€” Strange Printer | Hard | | | LC 689 โ€” Maximum Sum of 3 Non-Overlapping Subarrays | Hard | | | LC 1000 โ€” Minimum Cost to Merge Stones | Hard | | | LC 1092 โ€” Shortest Common Supersequence | Hard | | | LC 1235 โ€” Maximum Profit in Job Scheduling | Hard | | | CC โ€” LCS (LCSSTR) | Hard | | | CC โ€” Advanced DP (ADVDP) | Hard | | | CC โ€” Matrix Chain Multiplication (MATCHAIN) | Hard | |


โ† Back to Home ยท ยฉ sparshjaswal