Unbounded Knapsack Problem in DSA Typescript - Time & Space Complexity
We want to understand how the time needed to solve the Unbounded Knapsack problem grows as the input size increases.
Specifically, how the number of items and the knapsack capacity affect the work done.
Analyze the time complexity of the following code snippet.
function unboundedKnapsack(capacity: number, weights: number[], values: number[]): number {
const dp = new 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 copies of given items within the capacity.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Nested loops - outer loop over capacity, inner loop over 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 grows, the total operations increase by multiplying these two factors.
| Input Size (capacity n, items m) | Approx. Operations |
|---|---|
| n=10, m=5 | About 50 operations |
| n=100, m=5 | About 500 operations |
| n=1000, m=5 | About 5000 operations |
Pattern observation: Operations grow roughly by multiplying capacity and number of items.
Time Complexity: O(n * m)
This means the time needed grows proportionally with both the knapsack capacity and the number of items.
[X] Wrong: "The time depends only on the number of items, not the capacity."
[OK] Correct: The outer loop runs for each capacity value, so capacity directly affects total work.
Understanding this time complexity helps you explain how dynamic programming solves problems efficiently by breaking them into smaller parts.
"What if we used recursion with memoization instead of this bottom-up approach? How would the time complexity change?"
Practice
0/1 Knapsack Problem and the Unbounded Knapsack Problem?Solution
Step 1: Understand the item usage rules
In 0/1 Knapsack, each item can be chosen at most once. In Unbounded Knapsack, items can be chosen unlimited times.Step 2: Compare the problem constraints
Unbounded Knapsack allows repeated use of the same item, unlike 0/1 Knapsack.Final Answer:
In Unbounded Knapsack, you can use unlimited copies of each item. -> Option AQuick Check:
Unlimited item usage = In Unbounded Knapsack, you can use unlimited copies of each item. [OK]
- Confusing unbounded with fractional knapsack
- Thinking items cannot repeat
- Assuming fixed item count
Solution
Step 1: Check parameter types for correctness
Weight capacityWshould be a number, weightswtand valuesvalarrays of numbers, andnthe number of items as a number.Step 2: Identify the correct signature
function unboundedKnapsack(W: number, wt: number[], val: number[], n: number): number matches all types correctly. Others have wrong types like string instead of number.Final Answer:
function unboundedKnapsack(W: number, wt: number[], val: number[], n: number): number -> Option CQuick Check:
Correct types for all parameters = function unboundedKnapsack(W: number, wt: number[], val: number[], n: number): number [OK]
- Using string instead of number for weights or capacity
- Mixing array types
- Incorrect return type
const val = [10, 40, 50];
const wt = [1, 3, 4];
const W = 6;
function unboundedKnapsack(W: number, wt: number[], val: number[], n: number): number {
const dp = Array(W + 1).fill(0);
for (let i = 1; i <= W; i++) {
for (let j = 0; j < n; j++) {
if (wt[j] <= i) {
dp[i] = Math.max(dp[i], dp[i - wt[j]] + val[j]);
}
}
}
return dp[W];
}
console.log(unboundedKnapsack(W, wt, val, val.length));Solution
Step 1: Understand the DP array construction
We build dp array from 0 to W=6. For each capacity, we check all items and update dp[i] with max value including unlimited items.Step 2: Calculate dp values step-by-step
dp[1]=max(0, dp[0]+10)=10
dp[2]=max(0, dp[1]+10)=20
dp[3]=max(dp[3], dp[0]+40)=40, also dp[3]=max(40, dp[2]+10)=40
dp[4]=max(dp[4], dp[1]+40)=50, also dp[4]=max(50, dp[0]+50)=50
dp[5]=max(dp[5], dp[2]+40)=60, also dp[5]=max(60, dp[1]+50)=60
dp[6]=max(dp[6], dp[3]+40)=80, also dp[6]=max(80, dp[2]+50)=90Final Answer:
90 -> Option AQuick Check:
Max value for W=6 = 90 [OK]
- Not considering multiple copies of items
- Incorrect dp array updates
- Mixing 0/1 and unbounded logic
function unboundedKnapsack(W: number, wt: number[], val: number[], n: number): number {
const dp = Array(W + 1).fill(0);
for (let j = 0; j < n; j++) {
for (let i = 1; i <= W; i++) {
if (wt[j] <= i) {
dp[i] = Math.max(dp[i], dp[i - wt[j]] + val[j]);
}
}
}
return dp[W];
}Solution
Step 1: Analyze loop order for unbounded knapsack
For unbounded knapsack, outer loop should iterate over capacities (i), inner loop over items (j) to allow multiple uses of items.Step 2: Identify the bug in loop order
Here, outer loop is over items and inner over capacity, which is incorrect and leads to wrong results.Final Answer:
Loops are reversed; inner loop should be over items, outer over capacity -> Option DQuick Check:
Correct loop order = capacity outer, items inner [OK]
- Swapping loop order
- Wrong dp initialization
- Incorrect return index
val = [5, 10, 15] and weights wt = [1, 3, 4], and a knapsack capacity W = 7, what is the maximum value achievable using the Unbounded Knapsack approach?Solution
Step 1: Calculate dp array values for capacities 1 to 7
dp[0]=0
dp[1]=max(0, dp[0]+5)=5
dp[2]=max(0, dp[1]+5)=10
dp[3]=max(dp[3], dp[0]+10)=10, also dp[3]=max(10, dp[2]+5)=10
dp[4]=max(dp[4], dp[1]+10)=15, also dp[4]=max(15, dp[0]+15)=15
dp[5]=max(dp[5], dp[2]+10)=20, also dp[5]=max(20, dp[1]+15)=20
dp[6]=max(dp[6], dp[3]+10)=20, also dp[6]=max(20, dp[2]+15)=25
dp[7]=max(dp[7], dp[4]+10)=25, also dp[7]=max(25, dp[3]+15)=25Step 2: Find maximum value at capacity 7
The maximum value achievable is 25, but check if better combinations exist:
Try dp[7] = dp[3] + val[2] = 10 + 15 = 25
Try dp[7] = dp[4] + val[1] = 15 + 10 = 25
Try dp[7] = dp[6] + val[0] = 25 + 5 = 30 (better)
Update dp[7] = 30
Try dp[7] = dp[3] + val[2] = 10 + 15 = 25 (less than 30)
So final dp[7] = 30Final Answer:
30 -> Option BQuick Check:
Maximum value for W=7 = 30 [OK]
- Ignoring multiple item usage
- Stopping at first max value found
- Not updating dp array correctly
Ready to prove it?
Pass the test and this pattern moves unknown
