Dynamic programming (DP) scares a lot of people, but most interview DP problems use the same few ideas. This guide walks through them with short, tested Python solutions.
Every DP solution answers three questions:
dp[i] mean? Say it in one sentence before you write code.dp[i] from smaller answers?If you can’t say what dp[i] means in plain words, stop and work that out first.
ways[i] = the number of ways to reach step i. If you can take 1 to k steps at a time, you reach step
i from any of the k steps below it.
(session clip at 3:28)
def climbStairs(n, k=2):
ways = [0] * (n + 1)
ways[0] = 1
for i in range(1, n + 1):
for step in range(1, k + 1):
if i >= step:
ways[i] += ways[i - step]
return ways[n]
With k = 2 this is Fibonacci. You only ever look back k steps, so you can cut memory to O(k) later.
Can we split the numbers into two groups with the same sum? That is the same as: can some subset add up to half the total? Write down simple facts like this before you code. (session clip at 18:11)
can[s] = can some of the numbers seen so far add up to s?
def canPartition(nums):
total = sum(nums)
if total % 2:
return False
target = total // 2
can = [True] + [False] * target
for x in nums:
for s in range(target, x - 1, -1): # go down so each number is used once
can[s] = can[s] or can[s - x]
return can[target]
The inner loop goes down. If it went up, the same number could be used twice.
best[a] = the fewest coins that make amount a.
def coinChange(coins, amount):
INF = float("inf")
best = [0] + [INF] * amount
for a in range(1, amount + 1):
for c in coins:
if c <= a:
best[a] = min(best[a], best[a - c] + 1)
return -1 if best[amount] == INF else best[amount]
This is the trick most people miss. Counting ways to make an amount gives different answers depending on which loop is outside. (session clip at 61:30)
Coins outside counts combinations, so 1+2 and 2+1 are the same (Coin Change II, LeetCode 518):
def change(amount, coins):
ways = [1] + [0] * amount
for c in coins: # coins outside
for a in range(c, amount + 1):
ways[a] += ways[a - c]
return ways[amount]
Amounts outside counts orderings, so 1+2 and 2+1 are different (Combination Sum IV, LeetCode 377):
def combinationSum4(nums, target):
ways = [1] + [0] * target
for a in range(1, target + 1): # amounts outside
for x in nums:
if x <= a:
ways[a] += ways[a - x]
return ways[target]
Same lines, swapped loops, different problem.
Split n into at least two positive numbers and maximize their product. best[i] = the best product for
i. For each first piece j, either stop (j * (i - j)) or keep splitting the rest (j * best[i - j]).
(session clip at 70:30)
def integerBreak(n):
best = [0] * (n + 1)
best[1] = 1
for i in range(2, n + 1):
for j in range(1, i):
best[i] = max(best[i], j * (i - j), j * best[i - j])
return best[n]
For n = 10 the answer is 36 (3 + 3 + 4). It is easy to guess a rule here and get it wrong. The DP checks
every split, so it is safe.
ways[j] = the number of ways to form the first j letters of t from what we have read of s. When a
letter matches, every way to form the shorter prefix also extends to the longer one.
(session clip at 10:54)
def numDistinct(s, t):
ways = [1] + [0] * len(t)
for ch in s:
for j in range(len(t), 0, -1): # right to left, like subset sum
if t[j - 1] == ch:
ways[j] += ways[j - 1]
return ways[len(t)]
All solutions on this page were checked against brute force on thousands of random inputs.
| Problem | Pattern |
|---|---|
| Climbing Stairs (70) | Look back k steps |
| House Robber (198) | Take it or skip it |
| Partition Equal Subset Sum (416) | Subset sum, loop down |
| Coin Change (322) | Fewest items |
| Coin Change II (518) | Combinations, coins outside |
| Combination Sum IV (377) | Orderings, amounts outside |
| Integer Break (343) | Try every first piece |
| Longest Increasing Subsequence (300) | Best ending at i |
| Distinct Subsequences (115) | Two strings, loop down |
Dynamic programming problems (SDE Skills weekly session)
SDE Skills is a volunteer-run 501(c)(3) nonprofit with free daily LeetCode practice on Zoom. See the schedule and the free DSA practice sheet.