問題描述
給定不同面額的硬幣 和一個總金額 。編寫一個函數來計算可以湊成總金額所需的最小的硬幣個數、如果沒有任何一種硬幣組合能組成總金額,返回 。
輸入:
輸出:
解釋:
每種硬幣的數量是無限的
解題報告
動態規劃
表示組合成面額爲 的硬幣需要的硬幣個數,則:
貪心+回溯
這種實現方式源自題解區:lkaruga
。
貪心思想:
爲了使得總硬幣數目最少,優先使用大面值的硬幣,所以對 進行逆序排序;
回溯思想:
如果首先將大面值的硬幣使用了,則可能無法湊出目標值,所以需要進行回溯,依次減少大面值的硬幣數量
注意:最先找到不一定是最優解,所以其他情況我們也需要考慮。考慮其他情況時,合理使用剪枝,可以減少時間消耗。
實現代碼
動態規劃實現
int coinChange(vector<int>&coins,int amount){
vector<int>dp(amount+1,amount+1);
dp[0]=0;
for(int i=1;i<=amount;i++){
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]==amount+1)?-1:dp[amount];
}
};
貪心+回溯實現
class Solution{
public:
int coinChange(vector<int>&coins,int amount){
sort(coins.begin(), coins.end(),greater<int>());
int ans=INT_MAX;
dfs(coins, amount, 0, 0, ans);
return ans==INT_MAX?-1:ans;
}
void dfs(vector<int>&coins,int amount, int i, int count,int& ans){
if(amount==0){
ans=min(ans, count);
return;
}
if(i==coins.size()) return;
for(int k=amount/coins[i];k>=0&&k+count<ans;k--){
dfs(coins, amount-k*coins[i], i+1, count+k,ans);
}
}
};
參考資料
[1] Leetcode 322. 零錢兌換
[2] 題解區:lkaruga