Bird
Raised Fist0
Interview Prepdp-knapsackmediumAmazonGoogleMicrosoftGoldman_Sachs

0/1 Knapsack Problem

Choose your preparation mode4 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Steps
setup

Initialize dp array with zeros

Create a dp array of size W+1 (51) initialized to zero, representing maximum values achievable with capacities from 0 to 50 before processing any items.

💡 Initialization to zero means no items have been considered yet, so maximum value is zero for all capacities.
Line:dp = [0] * (W + 1)
💡 Starting with zeros sets the base case for the dynamic programming solution.
📊
0/1 Knapsack Problem - Watch the Algorithm Execute, Step by Step
Watching the algorithm fill the dp array from the bottom up reveals the dependency of each state on previous states, making the dynamic programming approach intuitive and clear.
Step 1/12
·Active fillAnswer cell
Initializing dp array
i\w012345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
i=000000000000000000000000000000000000000000000000000000
dp initialized to 0
Item 0 - wt:10 val:60
i\w012345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
i=000000000000000000000000000000000000000000000000000000
processing item 0
Item 0 - wt:10 val:60
i\w012345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
i=0000000000000000000000000000000000000000000000000000060
dp[50] updated to 60
Item 0 - wt:10 val:60
i\w012345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
i=00000000000000000000000000000000000000000000000000006060
dp[49] updated to 60
Item 0 - wt:10 val:60
i\w012345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
i=0000000000060606060606060606060606060606060606060606060606060606060606060606060606060606060606060
dp[10] updated to 60
Item 1 - wt:20 val:100
i\w012345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
i=0000000000060606060606060606060606060606060606060606060606060606060606060606060606060606060606060
processing item 1
Item 1 - wt:20 val:100
i\w012345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
i=00000000000606060606060606060606060606060606060606060606060606060606060606060606060606060606060160
dp[50] updated to 160
Item 1 - wt:20 val:100
i\w0123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
i=0000000000060606060606060606060606060606060606060601606060606060606060606060606060606060606060160
dp[30] updated to 160
Item 2 - wt:30 val:120
i\w0123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
i=00000000000606060606060606060601001001001001001001001001001001606060606060606060606060606060606060606060160
processing item 2
Item 2 - wt:30 val:120
i\w0123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
i=0000000000060606060606060606060100100100100100100100100100100160160160160160160160160160160160220220220220220220220220220220220
dp[50] updated to 220 (max value)
Item 2 - wt:30 val:120
i\w0123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
i=0000000000060606060606060606060100100100100100100100100100100160160160160160160160160180160180180180180180180180180180180220220
dp[40] updated to 180
Item 2 - wt:30 val:120
i\w01234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
i=0000000000060606060606060606060100100100100100100100100100100160160160160160160160160180160180180180180180180180180180180220
final answer dp[50] = 220

Key Takeaways

The dp array stores the maximum value achievable for each capacity, updated iteratively for each item.

This insight is hard to see from code alone because the dp array updates are subtle and depend on previous states.

Iterating capacities backwards prevents overwriting dp values needed for future calculations in the same iteration.

This backward iteration is a key trick that ensures correctness but is not obvious without visualization.

The final dp[W] value represents the optimal solution, combining items without exceeding capacity.

Seeing the dp array fill step-by-step clarifies how the algorithm builds up to the final answer.

Practice

(1/5)
1. Consider the following Python code for counting the number of ways to make change. What is the output when calling change(5, [1, 2, 5])?
easy
A. 5
B. 3
C. 4
D. 6

Solution

  1. Step 1: Initialize dp array

    dp = [1,0,0,0,0,0] since dp[0]=1.
  2. Step 2: Update dp for each coin

    For coin=1: dp becomes [1,1,1,1,1,1]; for coin=2: dp updates to [1,1,2,2,3,3]; for coin=5: dp updates to [1,1,2,2,3,4].
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    dp[5] = 4 matches known output [OK]
Hint: Trace dp updates coin by coin [OK]
Common Mistakes:
  • Off-by-one in dp indexing
  • Confusing permutations with combinations
2. You need to split a positive integer n into at least two positive integers such that the product of these integers is maximized. Which algorithmic approach guarantees finding the optimal solution efficiently?
easy
A. Pure brute force recursion exploring all partitions without memoization
B. A greedy approach that always cuts the integer into 3s and 2s
C. Dynamic programming using bottom-up tabulation with state representing maximum product for each integer up to n
D. Divide and conquer by splitting the integer into two halves recursively without caching results

Solution

  1. Step 1: Understand problem structure

    The problem requires maximizing product by splitting an integer into parts, which naturally fits a DP approach where subproblems represent maximum product for smaller integers.
  2. Step 2: Evaluate options

    Greedy (always cutting 3s) fails on some inputs; brute force recursion is correct but inefficient; divide and conquer without memoization repeats work. Bottom-up DP tabulation efficiently computes all subproblems and combines results.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    DP tabulation ensures optimal substructure and overlapping subproblems [OK]
Hint: DP tabulation handles overlapping subproblems optimally [OK]
Common Mistakes:
  • Believing greedy always works for integer break
  • Ignoring memoization in recursion
3. Consider the following Python function implementing the space-optimized subset sum algorithm. Given nums = [2, 3, 7] and S = 5, what is the value of dp[5] after processing all elements?
easy
A. True
B. False
C. IndexError due to out-of-range access
D. None (function does not return a boolean)

Solution

  1. Step 1: Trace dp array after processing num=2

    Initially dp=[True, False, False, False, False, False]. After num=2, dp[2]=True because dp[0] was True.
  2. Step 2: Trace dp array after processing num=3

    From w=5 down to 3, dp[5]=dp[5] or dp[2]=False or True -> True, dp[3]=dp[3] or dp[0]=False or True -> True.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Subset {2,3} sums to 5 -> dp[5] is True [OK]
Hint: Trace dp updates backward to avoid double counting [OK]
Common Mistakes:
  • Iterating dp forward causing overcounting
  • Off-by-one errors in dp indices
4. The following code attempts to solve the coin change minimum coins problem. Identify the line containing the subtle bug that causes incorrect results or infinite recursion for amount=0.
def coinChange(coins, amount):
    def dfs(rem):
        if rem == 0:
            return 0
        res = float('inf')
        for coin in coins:
            if rem - coin >= 0:
                res = min(res, 1 + dfs(rem - coin))
        return res
    ans = dfs(amount)
    return ans if ans != float('inf') else -1
medium
A. Line 3: Missing base case for rem < 0
B. Line 6: Missing check for rem == 0 before recursion
C. Line 9: Returning res without checking if res is still infinity
D. Line 7: Incorrect condition rem - coin >= 0 instead of rem >= coin

Solution

  1. Step 1: Analyze base cases in recursion

    Code handles rem == 0 but lacks base case for rem < 0, but since rem - coin >= 0 check prevents negative rem, no infinite recursion occurs.
  2. Step 2: Check return value correctness

    Returning res directly without checking if res is still infinity can cause incorrect results when no valid coin combination exists.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Must check if res is infinity before returning to handle no solution cases correctly [OK]
Hint: Check if result is infinity before returning in recursion [OK]
Common Mistakes:
  • Forgetting to handle no solution case
  • Assuming rem == 0 base case suffices
5. The following code attempts to compute the minimum number of perfect squares summing to n. Which line contains a subtle bug that can cause incorrect results or infinite loops?
medium
A. Line 3: Missing base case assignment dp[0] = 0
B. Line 2: dp initialization with infinity
C. Line 5: Outer loop from 1 to n
D. Line 7: Inner loop condition j*j <= i

Solution

  1. Step 1: Identify base case importance

    dp[0] = 0 is critical because it represents zero squares needed to sum to zero. Without it, dp[0] remains infinity, causing dp[i] updates to use invalid values.
  2. Step 2: Analyze impact of missing dp[0] = 0

    Since dp[0] is infinity, expressions like 1 + dp[i - j*j] become infinity, preventing dp[i] from ever updating correctly, leading to infinite loops or wrong results.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Missing dp[0] base case breaks DP initialization [OK]
Hint: dp[0] must be zero to start DP correctly [OK]
Common Mistakes:
  • Forgetting dp[0] initialization
  • Misplacing loop boundaries