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: Dynamic Programming (Bottom-Up)
Algorithm
- Let
dp[i]be the fewest number of coins needed to make amounti - Initialize
dp[0] = 0and every other entry to a large value (e.g.,amount + 1) - For each amount
ifrom 1 toamount, try every coin: ifi - coin >= 0, thendp[i] = min(dp[i], dp[i - coin] + 1) - If
dp[amount]is still the large sentinel value, return-1; otherwise returndp[amount]
Time & Space Complexity
- Time Complexity: O(amount × coins.length) - nested loop over amounts and coins
- Space Complexity: O(amount) - the
dparray
Java Implementation
import java.util.Arrays;
public class CoinChange {
/**
* Return the fewest number of coins needed to make up the amount.
* @param coins Coin denominations (unlimited supply)
* @param amount Target amount
* @return Minimum number of coins, or -1 if impossible
*/
public static int coinChange(int[] coins, int amount) {
int[] dp = new int[amount + 1];
Arrays.fill(dp, amount + 1);
dp[0] = 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];
}
// Test method
public static void main(String[] args) {
int[] coins1 = {1, 2, 5};
int amount1 = 11;
System.out.println("Input: coins = [1, 2, 5], amount = 11");
System.out.println("Output: " + coinChange(coins1, amount1)); // Expected: 3
int[] coins2 = {2};
int amount2 = 3;
System.out.println("Input: coins = [2], amount = 3");
System.out.println("Output: " + coinChange(coins2, amount2)); // Expected: -1
int[] coins3 = {1};
int amount3 = 0;
System.out.println("Input: coins = [1], amount = 0");
System.out.println("Output: " + coinChange(coins3, amount3)); // Expected: 0
}
}
Example Walkthrough
For coins = [1, 2, 5] and amount = 11:
dp[0] = 0dp[1] = min(dp[1], dp[0] + 1) = 1dp[2] = min(dp[2], dp[1] + 1, dp[0] + 1) = 1(using coin 2)- … and so on
dp[10] = min(dp[10], dp[5] + 1) = 2(two 5s)dp[11] = min(dp[11], dp[10] + 1, dp[6] + 1) = 3(5 + 5 + 1)
Answer: 3.
Key Points
- Unbounded Knapsack: Each coin has an unlimited supply
- Sentinel Value: Use
amount + 1to detect impossible amounts, avoiding overflow - Subproblem Structure:
dp[i]depends only on smaller amountsdp[i - coin] - Unreachable Amounts: If
dp[amount]remains the sentinel, return-1 - Zero Amount:
dp[0] = 0correctly returns 0 coins for amount 0