Overview
The 0/1 knapsack problem: given items with weights and values and a bag with capacity W, choose a subset with maximum total value whose weight fits. Each item is either taken once or not at all. The DP state dp[i][w] is the best value using the first i items with capacity w.
Knapsack is a family of patterns rather than one problem. Subset sum, partition equal subset sum, target sum, and 'ones and zeroes' are 0/1 knapsack. Coin change and rod cutting are unbounded knapsack, where each item can be reused. The difference shows up as the direction of the capacity loop in the 1D version.
You have a 7 kg limit and items with different weights and usefulness. For each item you ask: is it better to leave it out, or to pack it and use the best packing of the remaining capacity for everything before it?
When to use it
- Choose a subset under a budget (weight, cost, count) to maximize or minimize something.
- Can a subset reach an exact sum? How many subsets reach it?
- Split items into two groups with a target difference.
- Capacity values are small enough for an array (up to about 10^4 to 10^5).
Problem patterns it solves
Recognize it when: maximize value under a capacity; iterate capacity downward in 1D.
- 416. Partition Equal Subset Sum
- 1049. Last Stone Weight II
- 474. Ones and Zeroes
- 2915. Length of the Longest Subsequence That Sums to Target
Recognize it when: number of ways to pick items summing to k.
- 494. Target Sum
- 2787. Ways to Express an Integer as Sum of Powers
Recognize it when: items can be used any number of times; iterate capacity upward.
- 322. Coin Change
- 518. Coin Change II
- 279. Perfect Squares
Recognize it when: two budgets at once (zeros and ones, people and profit).
- 474. Ones and Zeroes
- 879. Profitable Schemes
Where it is used in real software
Selecting projects or ad campaigns with the highest expected return within a fixed budget.
Choosing which jobs to run on a machine with limited CPU and memory to maximize priority (multi-dimensional knapsack).
Logistics planners select shipments that maximize value within weight and volume limits.
The Merkle-Hellman cryptosystem was built on the hardness of subset sum (and was later broken).
Key terms
- Capacity W
- The budget limit.
- 0/1
- Each item is taken at most once.
- Unbounded
- Each item can be taken any number of times.
- Pseudo-polynomial
- O(n x W) depends on the numeric size of W, not just the input length.
How it works, step by step
- 1State
dp[i][w] = best value using items 0..i-1 with capacity w.
- 2Skip item i
dp[i][w] = dp[i - 1][w].
- 3Take item i if it fits
dp[i][w] = max(dp[i][w], dp[i - 1][w - weight] + value).
- 4Compress to 1D
For 0/1, loop w from W down to weight so each item is used once.
- 5Unbounded version
Loop w upward so dp[w - weight] may already include the same item.
0/1 knapsack, capacity 5
items (weight, value): A (1, 1), B (3, 4), C (4, 5). dp[w] after each item (1D, capacity loop downward)
| After item | w=0 | w=1 | w=2 | w=3 | w=4 | w=5 |
|---|---|---|---|---|---|---|
| none | 0 | 0 | 0 | 0 | 0 | 0 |
| A (1, 1) | 0 | 1 | 1 | 1 | 1 | 1 |
| B (3, 4) | 0 | 1 | 1 | 4 | 5 | 5 |
| C (4, 5) | 0 | 1 | 1 | 4 | 5 | 6 |
NOWAfter item: none | w=0: 0 | w=1: 0 | w=2: 0 | w=3: 0 | w=4: 0 | w=5: 0
Best value 6 with capacity 5: items A and C (weight 5). dp[5] after C = max(5, dp[1] + 5) = 6. Looping capacity downward guaranteed dp[1] still meant 'without C'.
Implementation
function knapsack01(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--) { // downward: each item once dp[w] = Math.max(dp[w], dp[w - weights[i]] + values[i]); } } return dp[W];} // 416. Partition Equal Subset Sum: can a subset sum to total / 2?function canPartition(nums) { const total = nums.reduce((a, b) => a + b, 0); if (total % 2) return false; const target = total / 2; const dp = new Array(target + 1).fill(false); dp[0] = true; for (const x of nums) { for (let s = target; s >= x; s--) dp[s] = dp[s] || dp[s - x]; } return dp[target];} // 494. Target Sum: count subsets P with sum(P) = (total + target) / 2function findTargetSumWays(nums, target) { const total = nums.reduce((a, b) => a + b, 0); if (Math.abs(target) > total || (total + target) % 2) return 0; const goal = (total + target) / 2; const dp = new Array(goal + 1).fill(0); dp[0] = 1; for (const x of nums) { for (let s = goal; s >= x; s--) dp[s] += dp[s - x]; } return dp[goal];}Complexity and performance
n items times capacity.
Needed for reconstruction.
Single array with the right loop direction.
Try every subset.
Trade-offs
When W is huge but n <= 40, split items into halves and combine subset sums (meet in the middle) instead of DP over capacity.
Fractional knapsack (items can be split) is solved greedily by value/weight ratio. 0/1 knapsack is not; greedy can be arbitrarily wrong.
Variants and related techniques
Each item has a limited count; split counts into powers of two to reduce to 0/1.
Use min instead of max with dp[0] = 0 and Infinity elsewhere.
Represent reachable sums as bits: bits |= bits << x, very fast in practice.
Common mistakes
- Looping capacity upward for 0/1 knapsack.
Fix: Upward reuses the same item multiple times; that is the unbounded version.
- Target Sum with an odd (total + target).
Fix: Return 0: no integer subset sum can satisfy it.
- Using greedy by ratio for 0/1.
Fix: Counterexample: capacity 50, items (10, 60), (20, 100), (30, 120). Greedy by ratio takes the first two items (160); the optimum takes the last two (220).
Interview questions
Why does the 1D 0/1 knapsack iterate capacity backward?
dp[w - weight] must still describe the solution without the current item. Iterating backward means those smaller capacities have not been updated yet in this round.
How is Partition Equal Subset Sum a knapsack problem?
It asks whether some subset has sum total / 2, which is 0/1 knapsack with capacity total / 2 and boolean values instead of maximum values.
Practice problems
| Problem | Difficulty | What it trains |
|---|---|---|
| 416. Partition Equal Subset Sum | Medium | Boolean 0/1 knapsack. |
| 494. Target Sum | Medium | Transform to subset count. |
| 1049. Last Stone Weight II | Medium | Closest sum to total / 2. |
| 474. Ones and Zeroes | Medium | Two-dimensional capacity. |
| 518. Coin Change II | Medium | Unbounded counting. |
| 879. Profitable Schemes | Hard | Capacity and threshold. |