Bird
Raised Fist0
Interview Prepdp-knapsackmediumAmazonFacebook

Target Sum

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

Calculate total sum and offset

We compute the total sum of nums (5) and set offset to this total to handle negative sums by shifting indices.

💡 Offsetting indices allows us to use a 1D array to represent sums from -total to +total as valid indices.
Line:total = sum(nums) offset = total
💡 Indexing sums with offset simplifies handling negative sums in the dp array.
📊
Target Sum - Watch the Algorithm Execute, Step by Step
Watching the dp array update step-by-step reveals how the algorithm counts combinations of plus and minus assignments to reach the target sum.
Step 1/23
·Active fillAnswer cell
Initializing dp array
i\w012345678910
i=0???????????
Initializing dp array
i\w012345678910
i=000000100000
dp[offset]=1
Item 0 - wt:1 val:0
i\w012345678910
i=000000100000
dp[offset]=1
Item 0 - wt:1 val:0
i\w012345678910
i=000000010000
dp[5]=1
Item 0 - wt:1 val:0
i\w012345678910
i=000001010000
dp[5]=1
Item 0 - wt:1 val:0
i\w012345678910
i=000001010000
dp[4]=1
Item 1 - wt:1 val:0
i\w012345678910
i=000001010000
dp[4]=1
Item 1 - wt:1 val:0
i\w012345678910
i=000000100000
dp[4]=1
Item 1 - wt:1 val:0
i\w012345678910
i=000010100000
dp[4]=1
Item 1 - wt:1 val:0
i\w012345678910
i=000010101000
dp[6]=1
Item 1 - wt:1 val:0
i\w012345678910
i=000010201000
dp[6]=1
Item 1 - wt:1 val:0
i\w012345678910
i=000010201000
dp[3]=1
Item 2 - wt:1 val:0
i\w012345678910
i=000010201000
dp[3]=1
Item 2 - wt:1 val:0
i\w012345678910
i=000001000000
dp[3]=1
Item 2 - wt:1 val:0
i\w012345678910
i=000101000000
dp[3]=1
Item 2 - wt:1 val:0
i\w012345678910
i=000101020000
dp[5]=2
Item 2 - wt:1 val:0
i\w012345678910
i=000103020000
dp[5]=2
Item 2 - wt:1 val:0
i\w012345678910
i=000103020100
dp[7]=1
Item 2 - wt:1 val:0
i\w012345678910
i=000103030100
dp[7]=1
Item 2 - wt:1 val:0
i\w012345678910
i=000103030100
dp[2]=1
Item 3 - wt:1 val:0
i\w012345678910
i=000103030100
dp[2]=1
Item 4 - wt:1 val:0
i\w012345678910
i=000103030100
dp[2]=1
Item 4 - wt:1 val:0
i\w012345678910
i=000104060500
Answer dp[8]=5

Key Takeaways

Offsetting indices allows handling negative sums in a single dp array.

This trick is not obvious from code alone but is crucial for indexing sums from -total to +total.

Using a separate next_dp array prevents overwriting dp during iteration, preserving previous state.

This ensures correct accumulation of counts without losing data mid-iteration.

Each dp cell accumulates counts of ways to reach a sum by adding or subtracting the current number.

Watching how counts shift left and right in dp clarifies how sums evolve step-by-step.

Practice

(1/5)
1. Consider the following code for computing the minimum number of perfect squares summing to n. What is the value of dp[4] after the outer loop iteration i = 4 completes?
easy
A. 4
B. 1
C. 3
D. 2

Solution

  1. Step 1: Trace dp[4] updates

    For i=4, j iterates over 1 and 2 because 1*1=1 <=4 and 2*2=4 <=4. - For j=1: dp[4] = min(inf, 1 + dp[3]) = 1 + dp[3] - For j=2: dp[4] = min(previous, 1 + dp[0]) = min(previous, 1 + 0) = 1 Since dp[0] = 0, dp[4] becomes 1.
  2. Step 2: Confirm dp[4] final value

    dp[4] = 1 means 4 can be represented as one perfect square (2*2). This matches the expected minimal count.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    dp[4] = 1 for 4 = 2^2 [OK]
Hint: dp[4] = 1 because 4 is a perfect square itself [OK]
Common Mistakes:
  • Off-by-one errors in loop
  • Ignoring dp[0] base case
2. The following code attempts to count the number of combinations to make change. Which line contains a subtle bug that causes it to count permutations instead of combinations?
medium
A. Line 5: inner loop iterating backwards over amounts
B. Line 4: outer loop over coins
C. Line 2: dp initialization
D. Line 6: updating dp[w] with dp[w - coin]

Solution

  1. Step 1: Understand iteration order effect

    Iterating amounts backwards causes dp to count permutations, not combinations.
  2. Step 2: Identify bug line

    Line 5 iterates w from amount down to coin, which breaks combination counting logic.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Forward iteration over amounts is required to count combinations correctly [OK]
Hint: Check direction of inner loop iteration [OK]
Common Mistakes:
  • Using backward iteration in 1D dp
  • Misplacing dp[0] initialization
3. Identify the bug in the following code snippet for counting ways to make change using 1D DP:
def count_ways_bug(coins, amount):
    dp = [0] * (amount + 1)
    dp[0] = 0
    for coin in coins:
        for w in range(amount, coin - 1, -1):
            dp[w] += dp[w - coin]
    return dp[amount]
What is the bug?
medium
A. dp[0] should be initialized to 1, not 0
B. The inner loop should iterate forwards from coin to amount, not backwards
C. The dp array size should be amount, not amount + 1
D. The return statement should return dp[0] instead of dp[amount]

Solution

  1. Step 1: Check base case initialization

    dp[0] represents ways to make amount 0, which must be 1 (empty combination), but here it is set to 0, causing all dp values to remain 0.
  2. Step 2: Verify loop direction

    Though iterating backwards is incorrect for unlimited coin usage, the critical bug causing zero results is dp[0] initialization.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Correct base case dp[0]=1 is essential for counting ways [OK]
Hint: dp[0] must be 1 to count empty combination [OK]
Common Mistakes:
  • Initializing dp[0] to 0 misses base case
  • Iterating amounts backwards in 1D DP misses combinations
  • Incorrect dp array size causes index errors
4. 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
5. Suppose the integer break problem is modified so that you can reuse the same integer parts multiple times (unbounded splits), and you want to find the maximum product. Which modification to the DP approach below correctly handles this variant?
def integer_break(n):
    dp = [0] * (n + 1)
    dp[1] = 1
    for i in range(2, n + 1):
        max_product = 0
        for j in range(1, i):
            max_product = max(max_product, max(j, dp[j]) * max(i - j, dp[i - j]))
        dp[i] = max_product
    return dp[n]
Options:
hard
A. Use a nested loop where for each i, iterate j from 1 to i and update dp[i] = max(dp[i], j * dp[i-j]) to allow reuse
B. Sort possible parts and greedily pick the largest part repeatedly to maximize product
C. Keep the same code but add memoization to avoid recomputation
D. Change inner loop to iterate over all j ≤ i and update dp[i] as max(dp[i], dp[i-j] * dp[j]) without max(j, dp[j])

Solution

  1. Step 1: Understand reuse requirement

    Allowing reuse means dp[i] depends on dp[i-j] multiplied by j (or dp[j]) where j can be reused multiple times.
  2. Step 2: Modify DP update

    Updating dp[i] = max(dp[i], j * dp[i-j]) correctly models unbounded splits by combining current part j and best product for remaining i-j.
  3. Step 3: Evaluate other options

    Change inner loop to iterate over all j ≤ i and update dp[i] as max(dp[i], dp[i-j] * dp[j]) without max(j, dp[j]) removes max(j, dp[j]) incorrectly; Keep the same code but add memoization to avoid recomputation adds memoization but doesn't change logic; Sort possible parts and greedily pick the largest part repeatedly to maximize product is greedy and fails on some inputs.
  4. Final Answer:

    Option A -> Option A
  5. Quick Check:

    Unbounded knapsack style DP uses dp[i] = max(dp[i], j * dp[i-j]) [OK]
Hint: Unbounded knapsack uses dp[i] = max(dp[i], j * dp[i-j]) [OK]
Common Mistakes:
  • Using greedy approach
  • Not adjusting DP recurrence for reuse