Pattern #24
Knapsack & Subset DP
AdvancedChoose items under a capacity or hit an exact sum/target.
When to use
0/1 choices of items with weights/values, partition equal subset, target sum with +/-.
Recognition cues
- Partition equal subset sum
- Target sum / coin change II
- Boolean reachable dp[cap]
Common pitfalls
- 0/1 vs unbounded loop order (backward vs forward)
- Half-sum overflow when total is odd
- Using 2D when 1D reverse iteration is enough
90-second recognition drill
Which pattern fits best?
- Partition equal subset sum
- Target sum / coin change II
- Boolean reachable dp[cap]
Interactive
Mental model
A full worked walkthrough of the invariant. Pause, scrub the dots, or use ← →. Aim to narrate each step yourself.
Step 1 of 8
0
1
2
3
4
5
dp[c] = best value
0/1 knapsack, capacity 5, items (2,3) and (3,4).
How to think about it
dp[c] = best value (or reachable bool) with capacity c. For 0/1, iterate capacity downward so each item is used once. For unbounded, iterate upward. Subset-sum is knapsack with value=weight and bool OR.
Template shapes
| Shape | Core move | Notes |
|---|---|---|
| 0/1 knapsack | c from W down to w | dp[c]=max(dp[c], dp[c-w]+v) |
| Unbounded | c from w to W | Coins, combos |
| Subset sum | bool dp | Partition / target |
Complexity baseline
O(n·W) time and O(W) space for classic knapsack.
From template to problem
- Identify 0/1 vs unbounded.
- Set capacity W (often sum/2).
- Init dp[0]=0 or true; fill per item.
- Read dp[W] or count of ways.
Template
Same skeleton in TypeScript, Python, and C#. Adapt the invariant; keep the structure.
Knapsack & Subset DP · Template
/** Knapsack template: partition equal subset sum (0/1 bool DP). */
export function canPartition(nums: number[]): boolean {
const sum = nums.reduce((a, b) => a + b, 0);
if (sum % 2) return false;
const target = sum / 2;
const dp = new Array<boolean>(target + 1).fill(false);
dp[0] = true;
for (const x of nums) {
for (let c = target; c >= x; c--) dp[c] = dp[c]! || dp[c - x]!;
}
return dp[target]!;
}
/** Knapsack template: partition equal subset sum (0/1 bool DP). */
export function canPartition(nums: number[]): boolean {
const sum = nums.reduce((a, b) => a + b, 0);
if (sum % 2) return false;
const target = sum / 2;
const dp = new Array<boolean>(target + 1).fill(false);
dp[0] = true;
for (const x of nums) {
for (let c = target; c >= x; c--) dp[c] = dp[c]! || dp[c - x]!;
}
return dp[target]!;
}
#StatusProblemTypeDifficultyDone
- 1#416 Partition Equal Subset SumGuidemedium
- 2#474 Ones and ZeroesGuidemedium
- 3#494 Target SumGuidemedium
- 4#518 Coin Change IIGuidemedium
- 5#879 Profitable SchemesGuidehard
- 6#1049 Last Stone Weight IIGuidemedium