Unbounded Knapsack Problem in DSA Javascript - Time & Space Complexity
We want to understand how the time needed to solve the Unbounded Knapsack problem grows as the input size changes.
Specifically, how does the number of items and the knapsack capacity affect the work done?
Analyze the time complexity of the following code snippet.
function unboundedKnapsack(capacity, weights, values) {
const dp = Array(capacity + 1).fill(0);
for (let c = 1; c <= capacity; c++) {
for (let i = 0; i < weights.length; i++) {
if (weights[i] <= c) {
dp[c] = Math.max(dp[c], dp[c - weights[i]] + values[i]);
}
}
}
return dp[capacity];
}
This code finds the maximum value achievable with unlimited items and a given knapsack capacity.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Nested loops: outer loop runs over capacities from 1 to capacity, inner loop runs over all items.
- How many times: Outer loop runs capacity times, inner loop runs number of items times for each capacity.
As capacity or number of items grow, the total operations grow by multiplying these two.
| Input Size (capacity n, items m) | Approx. Operations |
|---|---|
| n=10, m=5 | 10 * 5 = 50 |
| n=100, m=5 | 100 * 5 = 500 |
| n=1000, m=5 | 1000 * 5 = 5000 |
Pattern observation: Operations grow linearly with capacity and number of items multiplied together.
Time Complexity: O(n * m)
This means the time needed grows proportionally to the product of knapsack capacity and number of items.
[X] Wrong: "The time complexity is exponential because we can pick unlimited items repeatedly."
[OK] Correct: The dynamic programming approach avoids repeated work by storing results, so it only does a fixed number of operations based on capacity and items.
Understanding this time complexity helps you explain how dynamic programming improves efficiency over naive recursion, a key skill in problem solving.
"What if we changed the problem to 0/1 Knapsack (each item only once)? How would the time complexity change?"
Practice
Solution
Step 1: Understand 0/1 constraint
In 0/1 Knapsack each item has a binary choice - include once or exclude. After including, it cannot be reused.Step 2: Understand Unbounded constraint
In Unbounded Knapsack there is no limit on how many times an item can be selected. The same item can fill the bag.Step 3: Practical impact
This changes the recurrence: 0/1 uses dp[i-1][w-wt] (previous row); Unbounded uses dp[i][w-wt] (same row, enabling reuse).Final Answer:
Unbounded allows unlimited item repetition. -> Option BQuick Check:
Unbounded = unlimited copies. 0/1 = at most one per item. [OK]
- Confusing Unbounded with Fractional Knapsack
- Thinking 0/1 allows unlimited items
- Believing recursion vs iteration distinguishes them
Solution
Step 1: Left-to-right reuse
Computing dp[w] using dp[w - weight[i]] left-to-right means dp[w - weight[i]] has already been updated - it reflects using item i again. This is intentional reuse.Step 2: Contrast with 0/1
0/1 Knapsack goes right-to-left to prevent reuse - ensuring dp[w - weight[i]] holds the pre-item value.Final Answer:
Left-to-right enables intentional item reuse. -> Option BQuick Check:
Left-to-right = reuse. Right-to-left = no reuse. [OK]
- Thinking direction affects performance not semantics
- Not knowing left-to-right enables reuse
- Confusing with 0/1 which requires right-to-left
Solution
Step 1: Try repeating each item
Item 1 (w=1, v=10) × 6 = value 60. Item 2 (w=3, v=40) × 2 = value 80, weight=6 exactly. Item 3 (w=4, v=50) + item 1 × 2 = value 70.Step 2: Find maximum
Two copies of item 2 gives value 80 using exactly capacity 6 - this is the maximum.Final Answer:
80 -> Option BQuick Check:
Item 2 × 2: 40×2=80, weight 3×2=6. [OK]
- Only trying single-item combinations
- Not trying repeated use of the same item
- Confusing with 0/1 where each item used at most once
Solution
Step 1: Time complexity
Two nested loops - n items × W+1 capacities. Each cell O(1). Total O(n×W).Step 2: Space complexity
Only a 1D array dp[W+1] is needed, updated in place. Space O(W).Step 3: Contrast with 2D
Standard 2D DP uses O(n×W) space. 1D optimization reduces to O(W).Final Answer:
Time O(n×W), Space O(W) -> Option CQuick Check:
1D = O(n×W) time, O(W) space. [OK]
- Reporting O(n×W) space for 1D version
- Confusing with O(2^n) exponential recursion
- Forgetting 1D reduces space to O(W)
Solution
Step 1: Map coin change to Knapsack
Coin denominations = item weights. Target amount = capacity W. Each denomination usable unlimited times = Unbounded constraint.Step 2: Rule out other options
Job scheduling once per job = 0/1 Knapsack. Activity selection = greedy. Matrix chain = interval DP.Final Answer:
Coin change with unlimited denominations. -> Option BQuick Check:
Coin change = Unbounded. Coins used unlimited times, amount = capacity. [OK]
- Mapping job scheduling to Unbounded instead of 0/1
- Not recognizing coin change as Knapsack
- Thinking activity selection uses Unbounded DP
Ready to prove it?
Pass the test and this pattern moves unknown
