LeetCode第322題鏈接。
題目描述:
給定不同面額的硬幣 coins 和一個總金額 amount。編寫一個函數來計算可以湊成總金額所需的最少的硬幣個數。如果沒有任何一種硬幣組合能組成總金額,返回 -1。
例子:
輸入: coins =[1, 2, 5]
, amount =11
輸出:3
解釋: 11 = 5 + 5 + 1
解題:
一、思路:動態規劃;
1.dp[i]表示amount = i時,需要的硬幣數量;填充dp[],因爲dp[]最大爲amount個,所以將其初始化爲amount+1;
2.動態方程:dp[i] = Math.max(dp[i], dp[i - coins[j]] + 1);當前金額i所使用的金幣個數,是dp[i] 和i - coin[j]金額所使用的金幣個數dp[i - coin[i]] + 1,這裏加一是因爲coin[i],消耗一個金幣。
public class Solution {
public int coinChange(int[] coins, int amount) {
int max = amount + 1;
//dp[i] 表示amount = i時,需要的硬幣數量
int[] dp = new int[amount + 1];//dp[0] 到 dp[amount]
//填充dp[],因爲dp[]最大爲amount個,所以將其初始化爲amount+1
Arrays.fill(dp, max);
dp[0] = 0;
for (int i = 1; i <= amount; i++) {
for (int j = 0; j < coins.length; j++) {
if (coins[j] <= i) {
dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
}
}
}
return dp[amount] > amount ? -1 : dp[amount];
}
}
二、思路:遞歸;
1.先將硬幣面額排序, 用最大面額的金幣去組成amount。剩餘amount1 = amount - n * coins[coins.length - 1];此時需要n個金幣。
2.剩餘金額在用剩餘面額硬幣兌換,再考慮用coins.length - 2個最大面額硬幣, 剩餘金額在用剩餘面額硬幣兌換。【此處需要考慮,如果剩下面額金幣,不能兌換amount1呢?此時需要,將 amount1 變更爲amount1 = amount - (n-1) * coins[coins.length - 1]】再繼續用剩餘的金幣面額去兌換。
3.結束條件:amount == 0時,返回金幣個數。如果amount < 0,即金幣面額不能組成amount,則返回-1;
class Solution {
int miniAns;
public int coinChange(int[] coins, int amount) {
if (amount == 0) return 0;
Arrays.sort(coins);
miniAns = Integer.MAX_VALUE;
coinChangeL(coins, amount, coins.length - 1, 0);
miniAns = miniAns == Integer.MAX_VALUE? -1: miniAns;
return miniAns;
}
public void coinChangeL(int[] coins, int amount, int index, int cnt) {
if (amount == 0) {
miniAns = Math.min(cnt, miniAns);
return;
}
if (index < 0 || amount < 0) {
return;
}
for (int maxcoin = amount/coins[index]; maxcoin >= 0 && maxcoin + cnt < miniAns; maxcoin--) {
coinChangeL(coins, amount - maxcoin * coins[index], index - 1, cnt + maxcoin);
}
}
}
進階-題目描述LeetCode地址:
給定不同面額的硬幣和一個總金額。寫出函數來計算可以湊成總金額的硬幣組合數。假設每一種面額的硬幣有無限個。
例子:
輸入: amount = 5, coins = [1, 2, 5]
輸出: 4
解釋: 有四種方式可以湊成總金額:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1
解答:
1.動態規劃
思路:
1.狀態:dp[i]表示金額i的組成次數。很明顯當amount=0時,dp[0] = 1;
2.動態方程:dp[i] = dp[i] + dp[i - coins[j]];
class Solution {
public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;
for (int coin : coins) {
for (int x = coin; x < amount + 1; ++x) {
dp[x] += dp[x - coin];
}
}
return dp[amount];
}
}
2.遞歸法
超時。
class Solution {
int res;
public int change(int amount, int[] coins) {
if (amount == 0 ) return 1;
Arrays.sort(coins);
res = 0;
coinChangeL(coins, amount, coins.length - 1, 0);
return res;
}
public void coinChangeL(int[] coins, int amount, int index, int cnt) {
if (amount == 0) {
res++;
return;
}
if (index < 0 || amount < 0) {
return;
}
for (int maxcoin = amount/coins[index]; maxcoin >= 0; maxcoin--) {
coinChangeL(coins, amount - maxcoin * coins[index], index - 1, cnt + maxcoin);
}
}
}