Description
Coin Change
You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money.
Return the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.
You may assume that you have an infinite number of each kind of coin.
Example 1:
Input: coins = [1,2,5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1
Example 2:
Input: coins = [2], amount = 3
Output: -1
Example 3:
Input: coins = [1], amount = 0
Output: 0
Constraints:
1 <= coins.length <= 121 <= coins[i] <= 231 - 10 <= amount <= 104
Approach
- Bottom Up -> Check solution for the amount by subtracting the coin and add one
- Initialize array with 1 index and value amount + 1 so it can be used later too to return -1
- In simplest terms we
d[i]will tell us the coins required to reach theiamount we fill all with amount + 1 to show that it is impossible to reach and we fill 0 index with zero saying it takes 0 coin to reach 0 amount - The outer loop iterates over each possible amount from
1toamount. For each amounti, we try to figure out how to makeiusing the available coin denominations. - With inner loop we will check what was the solution if we remove the j coin and add one coin which is j, min condition is because initially we assigned a higher value to each index
Time: O(n*t) Space: O(t)- Where n is the length of the array coins and t is the given amount.
class Solution {
public int coinChange(int[] coins, int amount) {
int[] d = new int[amount + 1];
Arrays.fill(d,amount + 1);
d[0] = 0;
for (int i = 1; i <= amount; i++){
for (int j = 0; j < coins.length; j++) {
if (coins[j] <= i) {
d[i] = Math.min(d[i], d[i - coins[j]] + 1);
}
}
}
return d[amount] > amount ? -1 : d[amount];
}
}Brute Force Solution (Recursive / Top-Down DFS)
The intuitive brute-force approach explores all possible ways to form the target amount by trying every coin at each step.
- Idea: To make up an
amount, try subtracting each coin denomination fromamount. The problem then reduces to finding the minimum coins needed for the remaining amount and adding for the coin used. - Base Cases:
- If
amount == 0, 0 coins are needed. - If
amount < 0, it’s impossible (return infinity / impossible flag).
class Solution {
public int coinChange(int[] coins, int amount) {
int ans = helper(coins, amount);
return ans == Integer.MAX_VALUE ? -1 : ans;
}
private int helper(int[] coins, int rem) {
if (rem == 0) return 0;
if (rem < 0) return Integer.MAX_VALUE;
int minCoins = Integer.MAX_VALUE;
for (int coin : coins) {
int res = helper(coins, rem - coin);
if (res != Integer.MAX_VALUE) {
minCoins = Math.min(minCoins, res + 1);
}
}
return minCoins;
}
}
- Complexity:
- Time: where is
amountand iscoins.length(exponential due to recomputing the same amounts repeatedly). - Space: recursion stack depth.
Most Optimized Solution (Bottom-Up Dynamic Programming)
The solution already written in your editor is the most optimal and standard standard dynamic programming approach.
Why it’s optimal and intuitive to remember:
- Core Concept:
dp[i]represents the minimum number of coins needed to make amounti. - Transition: To find
dp[i], try taking every coin where . The cost would be1 + dp[i - c]. We take the minimum across all possible coins. - Initialization: Fill
dpwithamount + 1(a sentinel value acting as infinity, since you can never need more thanamountcoins if min coin is 1). Setdp[0] = 0.
class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount + 1];
Arrays.fill(dp, amount + 1);
dp[0] = 0; // 0 coins needed to make amount 0
for (int i = 1; i <= amount; i++) {
for (int coin : coins) {
if (coin <= i) {
dp[i] = Math.min(dp[i], dp[i - coin] + 1);
}
}
}
return dp[amount] > amount ? -1 : dp[amount];
}
}
- Complexity:
- Time: where is
coins.lengthand isamount. - Space: for the 1D DP table.