Unbounded Knapsack
Solve this ProblemTest Case 1:
Test Case 2:
Test Case 3:
Constraints
- ◆
1 ≤ weights.length = values.length ≤ 20 - ◆
1 ≤ weights[i], values[i] ≤ 100 - ◆
0 ≤ capacity ≤ 1000
Try the Dry Run
Don't just read the solution — watch it execute, one step at a time.
Approach & Solutions
Brute Force — Recursive Without Memoization
BruteThis is the same weight-and-value decision as the standard knapsack, except an item that's placed in the bag doesn't get used up — it can be placed in again as many times as it still fits. Every item is either skipped for good (move permanently to the next item, capacity unchanged) or taken once more (bank its value, use up its weight, and consider that same item again from the current capacity). Both choices are tried wherever an item still fits, and the larger of the two resulting totals is kept. Running out of items or capacity ends a path with whatever value has already been collected.
O(2^capacity)O(capacity)1class Solution {
2 private int[] weights;
3 private int[] values;
4
5 public int unboundedKnapsack(int[] weights, int[] values, int capacity) {
6 this.weights = weights;
7 this.values = values;
8 return solve(0, capacity);
9 }
10
11 private int solve(int i, int capacity) {
12 if (i == weights.length || capacity == 0) return 0;
13 if (weights[i] > capacity) return solve(i + 1, capacity);
14 int skip = solve(i + 1, capacity);
15 int take = values[i] + solve(i, capacity - weights[i]);
16 return Math.max(skip, take);
17 }
18}Optimal — Bottom-Up 1D DP
OptimalTrack, for every capacity from 0 up to the bag's full capacity, the best total value achievable using the items considered so far. The key difference from the one-copy-per-item version is the direction the inner sweep runs: going from each item's own weight up to the full capacity — rather than backward — means that when dp[w - weight] is looked up, it may already include this same item, which is exactly what allows it to be counted more than once. Every item can still be skipped (the value at that capacity stays whatever it already was) or taken (its value plus the best value at the capacity left over, possibly including itself again), and the larger of the two is kept. The entry at the full capacity holds the answer once every item has been swept through.
O(n × capacity)O(capacity)1class Solution {
2 public int unboundedKnapsack(int[] weights, int[] values, int capacity) {
3 int[] dp = new int[capacity + 1];
4 for (int i = 0; i < weights.length; i++) {
5 for (int w = weights[i]; w <= capacity; w++) {
6 dp[w] = Math.max(dp[w], values[i] + dp[w - weights[i]]);
7 }
8 }
9 return dp[capacity];
10 }
11}