Given coins of different denominations and a total amount, return the number of combinations (not permutations) that sum to amount. Each coin can be used unlimited times.
For each coin, decide how many to use (0, 1, 2, …). Recurse on remaining amount. Count all ways the remaining amount reaches 0.
Why it works
Exhaustive — tries every combination of coin counts.
Why we can do better
Problem: Overlapping subproblems. DP builds bottom-up: iterate coins in the outer loop (to avoid counting permutations) and amounts in the inner loop.
Java — Recursive
classSolution {
publicintchange(int amount, int[] coins) {
returndfs(coins, amount, 0);
}
privateintdfs(int[] coins, int rem, int idx) {
if (rem == 0) return1;
if (rem < 0) return0;
int ways = 0;
for (int i = idx; i < coins.length; i++) // start from idx to avoid permutations
ways += dfs(coins, rem - coins[i], i);
return ways;
}
}
Python — Recursive
classSolution:
defchange(self, amount: int, coins: list[int]) -> int:
defdfs(rem, idx):
if rem == 0: return1if rem < 0: return0return sum(dfs(rem - coins[i], i) for i in range(idx, len(coins)))
returndfs(amount, 0)
Metric
Value
Time
Exponential
Space
O(amount)
03
Section Three · Approach 2
Unbounded Knapsack DP — O(n · amount)
dp[a] = number of combinations to make amount a. Iterate coins in outer loop (ensures combinations, not permutations), amounts in inner loop forward (unbounded — can reuse coins).
💡 Mental model: Imagine a cashier filling a tip jar. She first tries all amounts using only pennies, then adds nickels to the mix, then dimes. By adding one denomination at a time, she counts combinations (1p+1p+1n is the same as 1n+1p+1p — only counted once). If she mixed denominations in the inner loop, she'd count both orderings separately — giving permutations instead.
Algorithm
dp[0] = 1 — one way to make amount 0 (use no coins).
For each coin: for a from coin to amount: dp[a] += dp[a - coin].
Return dp[amount].
🎯 When to recognize this pattern: "Count combinations (order doesn't matter) to reach target with unlimited supply." Coins outer, amounts inner = combinations. Amounts outer, coins inner = permutations (LC 377 Combination Sum IV). The loop order is the key distinction.
Combinations vs Permutations — the loop order: Outer coin loop means each coin type is "introduced" once. dp[a] accumulates ways using coins[0..i] only. Inner coin loop would recount 1+2 and 2+1 as different permutations.
LC 322 vs LC 518: LC 322 finds the minimum number of coins (uses min). LC 518 counts the number of combinations (uses +=). Same DP structure, different aggregation.
⚠ Common Mistake: Swapping the loop order — putting amounts in the outer loop and coins in the inner loop. This counts permutations (1+2 and 2+1 are different). For combinations, coins must be the outer loop so each denomination is "introduced" once.