You are given coins of different denominations and a total amount of money amount. Write a function to compute 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.
minCount[] - A memo to record visited & min coins for amount i
if minCount[i] == -1, visited, but not reachable
if minCount[i] == MAX, not visited
class Solution {
private static int MAX;
public int coinChange(int[] coins, int amount) {
if (amount < 1) {
return 0;
}
// A memo to record visited & min coins for amount i
int[] minCount = new int[amount + 1];
MAX = amount + 1;
Arrays.fill(minCount, MAX);
int min = coinChanger(coins, amount, minCount);
return min;
}
// minimum number of coins to sum to `amount`, if impossible, return -1
private int coinChanger(int[] coins, int amount, int[] minCount) {
if (amount == 0) {
return 0;
}
if (minCount[amount] != MAX) {
return minCount[amount];
}
int min = MAX;
for (int i = 0; i < coins.length; i++) {
if (amount >= coins[i]) {
int tmp = coinChanger(coins, amount - coins[i], minCount);
if (tmp != -1 && tmp < MAX) {
min = Math.min(min, tmp + 1);
}
}
}
minCount[amount] = min == MAX ? -1 : min;
return minCount[amount];
}
}
increasing i then the previous partial result dp[i - coin] is the result that has considered coin already
decreasing i then the previous partial result dp[i - coin] is the result that has not considered coin yet
/**
* @return number of ways to make sum s using repeated coins
*/
public static int coinrep(int[] coins, int s) {
int[] dp = new int[s + 1];
dp[0] = 1;
for (int coin : coins)
for (int i = coin; i <= s; i++)
dp[i] += dp[i - coin];
return dp[s];
}
/**
* @return number of ways to make sum s using non-repeated coins
*/
public static int coinnonrep(int[] coins, int s) {
int[] dp = new int[s + 1];
dp[0] = 1;
for (int coin : coins)
for (int i = s; i >= coin; i--)
dp[i] += dp[i - coin];
return dp[s];
}