Optimize 0/1 to bounded knapsack DP
Company: Google
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Onsite
Quick Answer: This question evaluates mastery of dynamic programming for knapsack problems, focusing on state formulation, space-time optimization, and reconstructing optimal item sets.
0/1 Knapsack with Solution Reconstruction
Constraints
- 0 <= n <= 1000
- 0 <= W <= 10000
- 0 <= weight[i], value[i]
- len(weight) == len(value) == n
- Each item may be selected at most once (0/1).
Examples
Input: ([2,3,4], [4,5,10], 7)
Expected Output: (15, [1, 2])
Explanation: Take items 1 (w3,v5) and 2 (w4,v10): total weight 7, value 15 — the headline dry-run case.
Input: ([1,2,3], [6,10,12], 5)
Expected Output: (22, [1, 2])
Explanation: Items 1 (w2,v10) + 2 (w3,v12) fill capacity 5 for value 22, beating item 0.
Hints
- Define dp[i][w] = best value using the first i items at capacity w. Transition: skip item i-1 (dp[i-1][w]) or take it if it fits (dp[i-1][w-weight[i-1]] + value[i-1]).
- To reconstruct, walk i from n down to 1: if dp[i][w] differs from dp[i-1][w], item i-1 was taken — subtract its weight from w and record the index.
- For O(W) space you can collapse to one row iterated w from W down to weight[i-1], but you lose the per-step history needed to reconstruct unless you save decision bits.
Bounded Knapsack via Binary Decomposition
Constraints
- 0 <= n <= 1000
- 0 <= W <= 10000
- 0 <= weight[i], value[i]
- 0 <= count[i]
- len(weight) == len(value) == len(count) == n
Examples
Input: ([2,3,4], [4,5,10], [3,1,2], 7)
Expected Output: 15
Explanation: Headline dry run: take one item 1 (w3,v5) + one item 2 (w4,v10) = weight 7, value 15. Using more copies of cheaper items can't beat it within capacity 7.
Input: ([2,3,4], [4,5,10], [1,1,1], 7)
Expected Output: 15
Explanation: All counts 1 — reduces to the 0/1 case, same optimum 15.
Hints
- Naively turning each item into count[i] separate 0/1 items works but is O(W * sum count[i]) — too slow when counts are large.
- Binary decomposition: 1 + 2 + 4 + ... + 2^(k-1) + r = count[i], and any 0..count[i] copies are reachable by picking a subset of these chunks. This drops the factor to sum log(count[i]).
- After decomposition it's plain 0/1 knapsack: one rolling array dp[w], iterate w from W down to chunk_weight so each chunk is used at most once.