Problem Overview
You are given an integer amount representing a total sum of money and an integer array coins representing the denominations of available coins.
Your task is to find the number of combinations that make up the given amount using any number of coins.
Each coin can be used unlimited times, but the order of coins doesn’t matter (i.e., {1,2} and {2,1} are the same combination).
Example 1:
Input: amount = 5, coins = [1,2,5] Output: 4 Explanation: There are four combinations: 5 = 5 5 = 2 + 2 + 1 5 = 2 + 1 + 1 + 1 5 = 1 + 1 + 1 + 1 + 1
Example 2:
Input: amount = 3, coins = [2] Output: 0 Explanation: No combination can make up 3 using only coin 2.
Example 3:
Input: amount = 10, coins = [10] Output: 1 Explanation: Only one combination (10 = 10).
Constraints:
1 <= coins.length <= 3001 <= coins[i] <= 50000 <= amount <= 5000
Intuition / Approach
This is a Dynamic Programming (DP) problem — it’s similar to the classic unbounded knapsack problem.
The key idea is:
- For each coin, determine how many ways you can form every amount from
0toamount. - If you can use the same coin multiple times, then the subproblem relation builds upon itself using previous states.
We define dp[i] as the number of combinations to make up amount i.
Thought Process:
- Start with
dp[0] = 1, because there’s exactly one way to make amount0— by choosing no coins. - For each coin, iterate through all possible amounts from that coin’s value up to the target
amount. - For each amount
i, add the number of combinations that make upi - cointodp[i].
This means you’re including one more coin of that type to extend the existing combinations.
Algorithm Steps
- Initialize a
dparray of sizeamount + 1with all elements0. - Set
dp[0] = 1. - Loop over each coin in
coins:- For each value from
cointoamount:- Update
dp[i] += dp[i - coin].
- Update
- For each value from
- After processing all coins,
dp[amount]will contain the number of combinations.
Java Code Implementation
public class CoinChangeII {
public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1; // One way to make amount 0 — no coins
for (int coin : coins) {
for (int i = coin; i <= amount; i++) {
dp[i] += dp[i - coin];
}
}
return dp[amount];
}
public static void main(String[] args) {
CoinChangeII solution = new CoinChangeII();
System.out.println(solution.change(5, new int[]{1, 2, 5})); // Output: 4
System.out.println(solution.change(3, new int[]{2})); // Output: 0
System.out.println(solution.change(10, new int[]{10})); // Output: 1
}
}
Step-by-Step Example
Example: amount = 5, coins = [1, 2, 5]
Initially:
dp = [1, 0, 0, 0, 0, 0]
After using coin = 1:
dp = [1, 1, 1, 1, 1, 1]
After using coin = 2:
dp = [1, 1, 2, 2, 3, 3]
After using coin = 5:
dp = [1, 1, 2, 2, 3, 4]
So, there are 4 combinations to make 5.
Complexity Analysis
Time Complexity: O(amount * number_of_coins)
- For each coin, we iterate through all amounts up to
amount.
Space Complexity: O(amount)
- We maintain a one-dimensional DP array of size
amount + 1.
Alternative Approach: 2D DP Table (for clarity)
We can also use a 2D DP table dp[i][j], where i is the number of coins considered and j is the target amount.
Formula:
dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i - 1]]
dp[i - 1][j]: excluding current coin.dp[i][j - coins[i - 1]]: including current coin.
Though conceptually easier, this takes O(n * amount) space, so the 1D version is preferred.
