要求:组成amount最少硬币数
思路:
法一:硬币可以无限使用,为完全背包问题,需要注意和01背包区别在于要顺序遍历,为什么?
https://blog.csdn.net/yandaoqiusheng/article/details/84929357
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
if(amount==0)return 0;
vector<int> dp(amount+1,amount+1);
dp[0]=0;
for(auto &coin:coins){
for(int j=coin;j<=amount;++j)
dp[j]=min(dp[j],dp[j-coin]+1);
}
return dp[amount]==amount+1?-1:dp[amount];
}
};
法二:抛开什么几把背包,这就是一道动态规划,明显dp[i]=min(dp[i],dp[i-coin]+1),i是amount,先遍历amount再coin。本题两种都对因为无所谓重复
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
if(amount==0)return 0;
vector<int> dp(amount+1,amount+1);
dp[0]=0;
for(int i=1;i<=amount;++i)
for(auto &coin:coins)
if(i>=coin)
dp[i]=min(dp[i],dp[i-coin]+1);
return dp[amount]==amount+1?-1:dp[amount];
}
};
法三:这种题深度优先第一个找到的不一定最优,深搜硬币从大到小也没用,因为贪心要一层来,而不是一竖。但是广度是,因为它是一层一层算完的。这里用一下深度,记忆化搜索,算过的不用再算,这里分解着来
class Solution {
public:
int dfs(vector<int>& count,int amount,vector<int>& coins,int maxnum){
if(count[amount]!=maxnum)return count[amount];
int mincount=maxnum;
for(int i=0;i<coins.size();++i)
if(amount>=coins[i]){
int tmp=dfs(count,amount-coins[i],coins,maxnum);
if(tmp!=-1)mincount=min(tmp,mincount);
}
if(mincount==maxnum)count[amount]=-1;
else count[amount]=mincount+1;
return count[amount];
}
int coinChange(vector<int>& coins, int amount) {
if(amount==0)return 0;
vector<int> count(amount+1,amount+1);
count[0]=0;
dfs(count,amount,coins,amount+1);
return count[amount]==amount+1?-1:count[amount];
}
};