Unbounded Knapsack Problem in DSA C# - 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.
int UnboundedKnapsack(int W, int[] wt, int[] val, int n) {
int[] dp = new int[W + 1];
for (int i = 0; i <= W; i++) {
for (int j = 0; j < n; j++) {
if (wt[j] <= i) {
dp[i] = Math.Max(dp[i], dp[i - wt[j]] + val[j]);
}
}
}
return dp[W];
}
This code finds the maximum value for a knapsack of capacity W using unlimited items from n types.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Nested loops: outer loop runs from 0 to W, inner loop runs over n items.
- How many times: Outer loop runs W+1 times, inner loop runs n times each outer iteration.
As the knapsack capacity W grows, the outer loop runs more times. For each capacity, we check all n items.
| Input Size (W) | Approx. Operations (n * W) |
|---|---|
| 10 | 10 * n |
| 100 | 100 * n |
| 1000 | 1000 * n |
Pattern observation: The work grows linearly with both the knapsack capacity and the number of items.
Time Complexity: O(n * W)
This means the time needed grows proportionally with the number of items and the knapsack capacity.
[X] Wrong: "Since items can be chosen unlimited times, the time complexity is exponential because of infinite choices."
[OK] Correct: The dynamic programming approach uses a table to store results for each capacity, avoiding repeated work, so the complexity is polynomial, not exponential.
Understanding this time complexity helps you explain how dynamic programming efficiently solves problems with repeated choices, a key skill in interviews.
"What if we used recursion without memoization? How would the time complexity change?"
Practice
Solution
Step 1: Understand 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 problem constraints
Unbounded Knapsack allows multiple copies 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 can only be chosen once
- Assuming fixed number of items to pick
Solution
Step 1: Check array size and initialization
The DP array size should be W+1 to cover capacities from 0 to W. Initializing with 0 is correct for max value problems.Step 2: Validate initialization values
Setting dp[i] = 0 means no value at start, which is correct. Negative or max int values are incorrect here.Final Answer:
int[] dp = new int[W + 1]; for (int i = 0; i <= W; i++) dp[i] = 0; -> Option AQuick Check:
DP array size W+1 and zero initialization = int[] dp = new int[W + 1]; for (int i = 0; i <= W; i++) dp[i] = 0; [OK]
- Using wrong array size (W instead of W+1)
- Initializing with int.MaxValue or int.MinValue incorrectly
- Starting loop from 1 instead of 0
int W = 5;
int[] wt = {1, 3, 4};
int[] val = {10, 40, 50};
int[] dp = new int[W + 1];
for (int i = 0; i <= W; i++) {
for (int j = 0; j < wt.Length; j++) {
if (wt[j] <= i) {
dp[i] = Math.Max(dp[i], dp[i - wt[j]] + val[j]);
}
}
}
Console.WriteLine(dp[W]);Solution
Step 1: Trace dp array updates for each capacity
Calculate dp values: - dp[0]=0 - dp[1]=max(dp[1], dp[0]+10)=10 - dp[2]=max(dp[2], dp[1]+10)=20 - dp[3]=max(dp[3], dp[0]+40, dp[2]+10)=max(0,40,30)=40 - dp[4]=max(dp[4], dp[1]+40, dp[3]+10, dp[0]+50)=max(0,50,50,50)=50 - dp[5]=max(dp[5], dp[2]+40, dp[4]+10, dp[1]+50)=max(0,60,60,60)=60 But re-check dp[5] carefully: dp[5] = max(dp[5], dp[5-1]+10=dp[4]+10=50+10=60, dp[5-3]+40=dp[2]+40=20+40=60, dp[5-4]+50=dp[1]+50=10+50=60) = 60Step 2: Recalculate carefully for maximum value
Check if multiple items can be combined: - For dp[5], try dp[5-1]+10=dp[4]+10=50+10=60 - For dp[4], dp[4-4]+50=dp[0]+50=50 - For dp[3], dp[3-3]+40=dp[0]+40=40 - For dp[2], dp[2-1]+10=dp[1]+10=10+10=20 - For dp[1], dp[1-1]+10=dp[0]+10=10 So dp[5] = 60Final Answer:
60 -> Option CQuick Check:
Maximum value for capacity 5 = 60 [OK]
- Not considering multiple copies of items
- Incorrect dp array indexing
- Mixing up weights and values
int W = 7;
int[] wt = {1, 3, 4};
int[] val = {10, 40, 50};
int[] dp = new int[W + 1];
for (int i = 0; i < W; i++) {
for (int j = 0; j < wt.Length; j++) {
if (wt[j] <= i) {
dp[i] = Math.Max(dp[i], dp[i - wt[j]] + val[j]);
}
}
}
Console.WriteLine(dp[W]);Solution
Step 1: Check loop ranges for dp array access
The dp array has size W+1, so valid indices are 0 to W inclusive. The outer loop runs only to i < W, missing dp[W].Step 2: Identify impact of loop range
Because dp[W] is not computed, the final answer dp[W] will be incorrect or default zero.Final Answer:
The outer loop should run from 0 to W inclusive (i <= W). -> Option DQuick Check:
Loop must cover full dp array size = The outer loop should run from 0 to W inclusive (i <= W). [OK]
- Using wrong loop bounds causing incomplete dp calculation
- Incorrect dp array size
- Wrong comparison operators in conditions
Solution
Step 1: Calculate dp array values for capacities 0 to 8
Initialize dp[0]=0. - dp[1]=0 (no item fits) - dp[2]=max(dp[2], dp[0]+50)=50 - dp[3]=max(dp[3], dp[0]+70)=70 - dp[4]=max(dp[4], dp[2]+50=50+50=100, dp[1]+70=0+70=70)=100 - dp[5]=max(dp[5], dp[0]+100=100, dp[3]+50=70+50=120, dp[2]+70=50+70=120)=120 - dp[6]=max(dp[6], dp[4]+50=100+50=150, dp[3]+70=70+70=140, dp[1]+100=0+100=100)=150 - dp[7]=max(dp[7], dp[5]+50=120+50=170, dp[4]+70=100+70=170, dp[2]+100=50+100=150)=170 - dp[8]=max(dp[8], dp[6]+50=150+50=200, dp[5]+70=120+70=190, dp[3]+100=70+100=170)=200Step 2: Check for better combinations
Try combining items differently: - Using four 2-weight items: 4*50=200 - Using two 3-weight + one 2-weight: 2*70+50=190 - Using one 5-weight + one 3-weight: 100+70=170 - Using one 5-weight + one 3-weight + one 2-weight (over capacity) No better than 200 found, but check dp[8] carefully: - dp[8] = max(200, 190, 170) = 200Step 3: Re-examine for missed combinations
Try dp[8] = dp[3] + dp[5] = 70 + 120 = 190 (less than 200) Try dp[8] = dp[2] + dp[6] = 50 + 150 = 200 Try dp[8] = dp[0] + 100 (weight 5) + dp[3] (weight 3) = 100 + 70 = 170 Try dp[8] = dp[4] + dp[4] = 100 + 100 = 200 Try dp[8] = dp[7] + dp[1] = 170 + 0 = 170 Try dp[8] = dp[6] + dp[2] = 150 + 50 = 200 Try dp[8] = dp[5] + dp[3] = 120 + 70 = 190 Try dp[8] = dp[8-5] + 100 = dp[3] + 100 = 70 + 100 = 170 Try dp[8] = dp[8-3] + 70 = dp[5] + 70 = 120 + 70 = 190 Try dp[8] = dp[8-2] + 50 = dp[6] + 50 = 150 + 50 = 200 No combination exceeds 200, so 200 is max.Final Answer:
200 -> Option BQuick Check:
Max value for capacity 8 = 200 [OK]
- Ignoring multiple copies of items
- Not checking all item combinations
- Incorrect dp array updates
Ready to prove it?
Pass the test and this pattern moves unknown
