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
Create a dp array of size amount+1 (6) initialized with zeros, then set dp[0] = 1 because there is exactly one way to make amount 0: use no coins.
💡 Setting dp[0] = 1 is the base case that allows building up counts for larger amounts.
Line:dp = [0] * (amount + 1)
dp[0] = 1
💡 The dp array represents counts of combinations for each amount; starting with dp[0] = 1 seeds the counting process.
fill_row
Start processing coin 1
Begin iterating over the first coin (value 1). This coin will be used to update dp for amounts from 1 to 5.
💡 Processing coins one by one allows us to accumulate combinations that include that coin.
Line:for coin in coins:
# coin = 1
💡 We will now add ways to make amounts by including coin 1 in all possible counts.
fill_cells
Update dp[1] using coin 1
For amount w=1, add dp[1 - 1] = dp[0] to dp[1]. Since dp[0] = 1, dp[1] becomes 1, meaning one way to make amount 1 using coin 1.
💡 This step shows how smaller amounts contribute to ways to make larger amounts by adding the current coin.
Line:dp[1] += dp[1 - 1] # dp[1] += dp[0]
💡 dp[1] now counts combinations including coin 1, starting from the base case dp[0].
fill_cells
Update dp[2] using coin 1
For amount w=2, add dp[2 - 1] = dp[1] to dp[2]. dp[1] is 1, so dp[2] becomes 1, representing one way to make amount 2 with coin 1.
💡 Each dp[w] accumulates ways from dp[w - coin], extending combinations by one coin.
Line:dp[2] += dp[2 - 1] # dp[2] += dp[1]
💡 The dp array is building up counts for all amounts reachable by coin 1.
fill_cells
Update dp[3] using coin 1
For amount w=3, add dp[3 - 1] = dp[2] to dp[3]. dp[2] is 1, so dp[3] becomes 1, counting one way to make 3 with coin 1.
💡 This step continues the pattern of extending combinations by adding coin 1 repeatedly.
Line:dp[3] += dp[3 - 1] # dp[3] += dp[2]
💡 The dp array now reflects ways to make amounts 0 to 3 using only coin 1.
fill_cells
Update dp[4] using coin 1
For amount w=4, add dp[4 - 1] = dp[3] to dp[4]. dp[3] is 1, so dp[4] becomes 1, representing one way to make 4 with coin 1.
💡 This step shows the incremental build-up of combinations for amount 4.
Line:dp[4] += dp[4 - 1] # dp[4] += dp[3]
💡 The dp array now has counts for amounts 0 to 4 using coin 1.
fill_cells
Update dp[5] using coin 1
For amount w=5, add dp[5 - 1] = dp[4] to dp[5]. dp[4] is 1, so dp[5] becomes 1, counting one way to make 5 with coin 1.
💡 This completes the dp array update for coin 1, showing all ways using only coin 1.
Line:dp[5] += dp[5 - 1] # dp[5] += dp[4]
💡 The dp array now fully represents ways to make amounts 0 to 5 using coin 1.
fill_row
Start processing coin 2
Move to the second coin (value 2). We will update dp for amounts from 2 to 5 by adding combinations that include coin 2.
💡 Processing the next coin adds new combinations that include coin 2, increasing counts where applicable.
Line:for coin in coins:
# coin = 2
💡 We will now add ways to make amounts by including coin 2 in addition to previous coins.
fill_cells
Update dp[2] using coin 2
For amount w=2, add dp[2 - 2] = dp[0] to dp[2]. dp[0] is 1, so dp[2] becomes 2, counting ways with coin 1 and coin 2.
💡 This step shows how coin 2 adds new combinations for amount 2.
Line:dp[2] += dp[2 - 2] # dp[2] += dp[0]
💡 dp[2] now counts combinations using coins 1 and 2.
fill_cells
Update dp[3] using coin 2
For amount w=3, add dp[3 - 2] = dp[1] to dp[3]. dp[1] is 1, so dp[3] becomes 2, counting combinations with coins 1 and 2.
💡 This step extends combinations for amount 3 by including coin 2.
Line:dp[3] += dp[3 - 2] # dp[3] += dp[1]
💡 dp[3] now reflects all ways to make 3 using coins 1 and 2.
fill_cells
Update dp[4] using coin 2
For amount w=4, add dp[4 - 2] = dp[2] to dp[4]. dp[2] is 2, so dp[4] becomes 3, counting combinations with coins 1 and 2.
💡 This step shows how dp[4] accumulates more combinations including coin 2.
Line:dp[4] += dp[4 - 2] # dp[4] += dp[2]
💡 dp[4] now counts all ways to make 4 using coins 1 and 2.
fill_cells
Update dp[5] using coin 2
For amount w=5, add dp[5 - 2] = dp[3] to dp[5]. dp[3] is 2, so dp[5] becomes 3, counting combinations with coins 1 and 2.
💡 This step completes dp updates for coin 2, increasing ways to make 5.
Line:dp[5] += dp[5 - 2] # dp[5] += dp[3]
💡 dp[5] now counts all ways to make 5 using coins 1 and 2.
fill_row
Start processing coin 5
Move to the last coin (value 5). We will update dp for amount 5 by adding combinations that include coin 5.
💡 Processing the largest coin last adds combinations that use coin 5 directly.
Line:for coin in coins:
# coin = 5
💡 We will add ways to make amount 5 by including coin 5.
fill_cells
Update dp[5] using coin 5
For amount w=5, add dp[5 - 5] = dp[0] to dp[5]. dp[0] is 1, so dp[5] becomes 4, counting all combinations including coin 5.
💡 This step adds the combination using coin 5 alone to the total count for amount 5.
Line:dp[5] += dp[5 - 5] # dp[5] += dp[0]
💡 dp[5] now holds the total number of ways to make amount 5 using all coins.
reconstruct
Return final answer
Return dp[amount] which is dp[5] = 4, representing the total number of combinations to make amount 5 with coins [1, 2, 5].
💡 Reading the final dp cell gives the answer to the problem.
Line:return dp[amount]
💡 The dp array's last cell holds the total count of combinations.
def change(amount, coins):
dp = [0] * (amount + 1) # STEP 1 initialize dp
dp[0] = 1 # STEP 1 base case
for item_index, coin in enumerate(coins): # STEP 2, 8, 13 iterate coins
for w in range(coin, amount + 1): # STEP 3-7, 9-12, 14 iterate amounts
dp[w] += dp[w - coin] # STEP fill dp[w]
return dp[amount] # STEP 15 return answer
if __name__ == '__main__':
print(change(5, [1, 2, 5])) # Output: 4
📊
Coin Change II (Count Ways) - Watch the Algorithm Execute, Step by Step
Watching each update to the dp array reveals how the algorithm counts combinations incrementally, which is hard to grasp from code alone.
Step 1/15
·Active fill★Answer cell
Initializing dp array
i\w
0
1
2
3
4
5
i=0
1
0
0
0
0
0
dp[0] = 1 (base case)
Item 0 - wt:1 val:0
i\w
0
1
2
3
4
5
i=0
1
0
0
0
0
0
dp array before coin 1 updates
Item 0 - wt:1 val:0
i\w
0
1
2
3
4
5
i=0
1
1
0
0
0
0
dp[1] updated
Item 0 - wt:1 val:0
i\w
0
1
2
3
4
5
i=0
1
1
1
0
0
0
dp[2] updated
Item 0 - wt:1 val:0
i\w
0
1
2
3
4
5
i=0
1
1
1
1
0
0
dp[3] updated
Item 0 - wt:1 val:0
i\w
0
1
2
3
4
5
i=0
1
1
1
1
1
0
dp[4] updated
Item 0 - wt:1 val:0
i\w
0
1
2
3
4
5
i=0
1
1
1
1
1
1
dp[5] updated
Item 1 - wt:2 val:0
i\w
0
1
2
3
4
5
i=0
1
1
1
1
1
1
dp array before coin 2 updates
Item 1 - wt:2 val:0
i\w
0
1
2
3
4
5
i=0
1
1
2
1
1
1
dp[2] updated
Item 1 - wt:2 val:0
i\w
0
1
2
3
4
5
i=0
1
1
2
2
1
1
dp[3] updated
Item 1 - wt:2 val:0
i\w
0
1
2
3
4
5
i=0
1
1
2
2
3
1
dp[4] updated
Item 1 - wt:2 val:0
i\w
0
1
2
3
4
5
i=0
1
1
2
2
3
3
dp[5] updated
Item 2 - wt:5 val:0
i\w
0
1
2
3
4
5
i=0
1
1
2
2
3
3
dp array before coin 5 updates
Item 2 - wt:5 val:0
i\w
0
1
2
3
4
5
i=0
1
1
2
2
3
4
dp[5] updated (final)
Item 2 - wt:5 val:0
i\w
0
1
2
3
4
5
i=0
1
1
2
2
3
4
Answer: 4 ways
Key Takeaways
✓ The dp array accumulates counts of combinations incrementally for each amount and coin.
This insight is hard to see from code alone because the dp array updates are subtle and cumulative.
✓ Processing coins in order ensures combinations are counted without duplicates, reflecting the unbounded knapsack pattern.
Visualizing the order of updates clarifies why the order of coins matters.
✓ Each dp[w] depends on dp[w - coin], showing how smaller subproblems build solutions to larger amounts.
Seeing these dependencies visually helps understand the dynamic programming recurrence.
Practice
(1/5)
1. Consider the following code snippet implementing the minimum cost for tickets problem. What is the value of dp[0] after the loop completes for the input days = [1,4,6] and costs = [2,7,15]?
2. You are given a set of positive integers and need to partition it into two subsets such that the absolute difference of their sums is minimized. Which algorithmic approach guarantees an optimal solution for this problem?
easy
A. Greedy algorithm that sorts and assigns elements alternately to subsets
B. Dynamic programming using a subset-sum style approach to find achievable sums
C. Divide and conquer by recursively splitting the array into halves
D. Sorting and then pairing elements from opposite ends to balance sums
Solution
Step 1: Understand problem constraints
The problem requires minimizing the difference between sums of two subsets, which is a classic partition problem variant.
Step 2: Identify algorithmic pattern
Greedy or divide-and-conquer approaches do not guarantee minimal difference. Dynamic programming, specifically subset-sum style DP, can find all achievable sums up to total_sum, enabling minimal difference calculation.
Hint: Minimal difference requires subset-sum DP, not greedy [OK]
Common Mistakes:
Assuming greedy or sorting suffices for minimal difference
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
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.
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.
Final Answer:
Option A -> Option A
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. You are given an array of integers and a target integer. You want to assign either a plus or minus sign to each integer such that the resulting sum equals the target. Which algorithmic approach guarantees finding the total number of such assignments efficiently?
easy
A. Sorting the array and using two pointers to find pairs that sum to the target
B. Greedy algorithm that picks signs based on local sum minimization
C. Dynamic programming using a 0/1 knapsack-like approach with state representing achievable sums
D. Divide and conquer by splitting the array and combining results without memoization
Solution
Step 1: Understand problem constraints
The problem requires counting all sign assignments to reach a target sum, which involves exploring exponential combinations.
Step 2: Identify suitable algorithmic pattern
Greedy and two-pointer approaches fail because they do not consider all combinations. Divide and conquer without memoization is exponential. DP with states representing achievable sums efficiently counts all valid assignments.
Final Answer:
Option C -> Option C
Quick Check:
DP handles overlapping subproblems and sums efficiently [OK]
Hint: Counting sign assignments requires DP over sums [OK]
Common Mistakes:
Thinking greedy or sorting solves counting sign assignments
5. The following code attempts to solve the Target Sum problem using bottom-up DP with offset indexing. Which line contains a subtle bug that causes incorrect results on inputs containing zero?
medium
A. Line 12-15: Updating dp array in-place instead of using a separate next_dp
B. Line 6: dp[offset] = 1
C. Line 10: if dp[s] != 0:
D. Line 8: for num in nums:
Solution
Step 1: Identify DP update method
The code updates dp in-place during iteration over sums, causing double counting when num=0 or overlapping states.
Step 2: Understand impact on zero values
Zero does not change sum, so updating dp in-place doubles counts incorrectly. Using a separate next_dp array avoids this.
Final Answer:
Option A -> Option A
Quick Check:
In-place updates cause state reuse within iteration, breaking correctness [OK]
Hint: In-place dp updates cause double counting with zero values [OK]