LeetCode 322:零錢兌換(動態規劃)
給定不同面額的硬幣 coins 和一個總金額 amount。編寫一個函數來計算可以湊成總金額所需的最少的硬幣個數。如果沒有任何一種硬幣組合能組成總金額,返回 -1。
示例 1:
輸入: coins = [1, 2, 5], amount = 11
輸出: 3
解釋: 11 = 5 + 5 + 1
示例 2:
輸入: coins = [2], amount = 3
輸出: -1
說明:
你可以認爲每種硬幣的數量是無限的。
dp解法:
**思路:**dp[N] = MIN{dp[N-coins[0], dp[N-coins[1]],…dp[N-coins[N]] }+1;
int coinChange(vector<int>& coins, int amount) {
long dp[amount+1] ={INT_MAX};
dp[0] = 0;
for(int i = 1; i < amount + 1 ; i++) {
dp[i] = INT_MAX;
for(int j = 0; j < coins.size(); j++) {
if(i >= coins[j]) {
dp[i] = min(dp[i], (dp[i - coins[j]] + 1));
}
}
}
return dp[amount] == INT_MAX ? -1 : dp[amount] ;
}
另一種更快的解法
先將硬幣面額從大到小排序, 再從最大面額的個數開始分支。即先考慮用n個最大面額硬幣, 剩餘金額在用剩餘面額硬幣兌換; 再考慮用n-1個最大面額硬幣, 剩餘金額在用剩餘面額硬幣兌換…依次類推。再進行剪枝, 若已用數量已大於最小數量, 則無續再往下討論。
int coinChange(vector<int>& coins, int amount) {
if (amount == 0) return 0;
sort(coins.rbegin(), coins.rend());
int miniAns = INT_MAX;
coinChangeIter(coins, amount, 0, 0, miniAns);
miniAns = (miniAns == INT_MAX) ? -1 : miniAns;
return miniAns;
}
void coinChangeIter(vector<int>& coins, int amount, int index, int count, int& miniAns){//amount: 目標值 coins:硬幣數組 index: 有效硬幣數組範圍 count: 已使用硬幣數 miniAns: 當前最小值
if (amount == 0){ //遍歷到最後,有解
miniAns = count < miniAns ? count : miniAns;
return;
}
if (index == coins.size())
return; //遍歷到最後,無解
for (int maxCoinNum = amount / coins[index]; maxCoinNum >= 0 && maxCoinNum + count < miniAns; maxCoinNum--){
coinChangeIter(coins, amount - maxCoinNum * coins[index], index + 1, count + maxCoinNum, miniAns);
}
}
自己的再版(31% 18%)
int coinChange(vector<int>& coins, int amount) {
if (amount == 0) return 0;
sort(coins.begin(), coins.end());
if (amount < coins[0]) return -1;
vector<int> res(amount + 1, INT_MAX); res[0] = 0;
for (int i = coins[0]; i < amount + 1; i++) {
int minvalue = res[i - coins[0]];
for (int j = 0; j < coins.size(); j++) {
if (i - coins[j] >= 0 && res[i - coins[j]] < minvalue)
minvalue = res[i - coins[j]];
}
if (minvalue != INT_MAX)
res[i] = 1 + minvalue;
}
return res[amount] == INT_MAX ? -1 : res[amount];
}
自己的初版(時空複雜度墊底5%,5%)
int coinChange(vector<int>& coins, int amount) {
if(amount==0) return 0;
sort(coins.begin(), coins.end());
if (amount < coins[0]) return -1;
vector<int> res(amount + 1, INT_MAX); res[0] = 0;
for (int i = coins[0]; i < amount + 1; i++) {
vector<int> findmin;
for (int j = 0; j < coins.size(); j++) {
if (i - coins[j] >= 0) findmin.push_back(res[i - coins[j]]);
}
if (findmin.size() != 0) {
int minvalue = *min_element(findmin.begin(), findmin.end());
if (minvalue != INT_MAX)
res[i] = 1 + minvalue;
}
}
return res[amount] == INT_MAX ? -1 : res[amount];
}