Ways to make an amount
Given an amount and a list of distinct coin values coins, with an unlimited supply of each,
return the number of combinations of coins that add up to the amount. Combinations that differ only in order count
once. If the amount is 0, there is one way: no coins.
Examples
| Input | Output | Why |
|---|---|---|
amount = 5, coins = [1,2,5] | 4 | 5; 2+2+1; 2+1+1+1; 1+1+1+1+1. |
amount = 3, coins = [2] | 0 | Odd amounts cannot be made from 2s. |
amount = 0, coins = [7] | 1 | The empty combination. |
Constraints
- 1 ≤ coins.length ≤ 300
- 1 ≤ coins[i] ≤ 5000, all distinct
- 0 ≤ amount ≤ 5000
- The answer fits in a 64-bit integer
Hints
Hint 1
ways[0] = 1. For each coin, ways[a] += ways[a − coin] for a from coin upwards.
Hint 2
Coins must be on the outer loop. With amounts outside, 1 + 2 and 2 + 1 are counted separately.
Where people lose marks
- Amounts on the outer loop, which counts ordered sequences (9 instead of 4 for the first example).
- Starting with ways[0] = 0, which makes every count 0.
- Overflow in 32-bit integers for large inputs.
Dry run on 5,[1,2,5]
Read it one frame at a time, the way you would trace the code on paper in an interview. Each frame shows the state after the step it describes.
-
Step 1 / 4ways100102030405
One way to make 0.
-
Step 2 / 4ways101112131415
Allow coin 1: ways[a] += ways[a − 1], a upwards from 1.
-
Step 3 / 4ways101122233435
Allow coin 2: ways[a] += ways[a − 2], a upwards from 2.
-
Step 4 / 4ways101122233445
Allow coin 5: ways[a] += ways[a − 5], a upwards from 5. The answer is ways[5] = 4.
How to think about it
This is the unbounded knapsack with sum in place of max. Process coin types one at a time; after processing the first
i types, ways[a] is the number of combinations of those types that make a. Adding coin c updates
ways[a] += ways[a − c] for a increasing from c, where ways[a − c] already includes combinations
that use c, which is what allows several copies.
Because each coin type is introduced once, in a fixed order, every combination is built in exactly one way: the disjointness check from the recurrence lesson.
Complexity. Time O(coins · amount) · Space O(amount)
The solution, in six languages
Each one is compiled and run against the test table before it is published. Java is reviewed by hand.
def count_ways(amount, coins):
ways = [1] + [0] * amount # one way to make 0
for c in coins: # coins outside: combinations, not sequences
for a in range(c, amount + 1):
ways[a] += ways[a - c]
return ways[amount]#include <vector>
long long solve(int amount, const std::vector<int>& coins) {
std::vector<long long> ways(amount + 1, 0);
ways[0] = 1;
for (int c : coins) // coins outside: combinations
for (int a = c; a <= amount; ++a) ways[a] += ways[a - c];
return ways[amount];
}class Solution {
public long countWays(int amount, int[] coins) {
long[] ways = new long[amount + 1];
ways[0] = 1;
for (int c : coins) // coins outside: combinations
for (int a = c; a <= amount; a++) ways[a] += ways[a - c];
return ways[amount];
}
}function countWays(amount, coins) {
const ways = [1, ...new Array(amount).fill(0)];
for (const c of coins) // coins outside: combinations
for (let a = c; a <= amount; a++) ways[a] += ways[a - c];
return ways[amount];
}fn solve(amount: i64, coins: &[i64]) -> i64 {
let n = amount as usize;
let mut ways = vec![0i64; n + 1];
ways[0] = 1;
for &c in coins { // coins outside: combinations
for a in (c as usize)..=n {
ways[a] += ways[a - c as usize];
}
}
ways[n]
}solve :: Int -> [Int] -> Int
solve amount coins = foldl addCoin (1 : replicate amount 0) coins !! amount
where
-- with coin c allowed: new[a] = old[a] + new[a - c], built left to right
addCoin old c = new
where new = zipWith (+) old (replicate c 0 ++ new)
Variants to try
- Count ordered sequences instead (swap the loops): the number of ways to climb stairs with the given step sizes.
- Each coin may be used at most once: loop amounts downwards.
- The fewest coins instead of the number of ways (Coin Change I).
Next problems
The cheapest way up a staircase
Each step has a cost; climb one or two steps at a time; start on step 0 or 1. Return the cheapest way past the top.
Open the problem → Medium15 minCan a subset reach the target?
Decide whether some subset of positive integers adds up to exactly the target. A boolean array over totals, filled downwards for each number.
Open the problem → Medium15 minCount the palindromic substrings
Count every contiguous substring that reads the same backwards, counting different positions separately. Each successful expansion step is one more.
Open the problem →Write a solution and run it against the real test table.
Keep going
The cheapest way up a staircase
Each step has a cost; climb one or two steps at a time; start on step 0 or 1. Return the cheapest way past the top.
Open the problem → Medium15 minCan a subset reach the target?
Decide whether some subset of positive integers adds up to exactly the target. A boolean array over totals, filled downwards for each number.
Open the problem → Medium15 minCount the palindromic substrings
Count every contiguous substring that reads the same backwards, counting different positions separately. Each successful expansion step is one more.
Open the problem → Dynamic programmingThe pattern behind it
Write the recursion, notice the repeats, fill a table in an order that makes each entry final.
Read the pattern →Preparing for a real process? Quant interview preparation, or book a free 20-minute call.