322. 零钱兑换(完全背包问题)
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1
。
示例 1:
输入: coins =[1, 2, 5]
, amount =11
输出:3
解释: 11 = 5 + 5 + 1
示例 2:
输入: coins =[2]
, amount =3
输出: -1
说明:
你可以认为每种硬币的数量是无限的。
解题思路:
1. 动态规划
-
背包问题
- 01背包,选和不选的问题
- 完全背包,选几个的问题->转化成背包问题解决
- 多重背包,即每个物品有限个
记录0-amount内,每种金额所需的最少硬币数
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
vector<int> dp(amount+1,INT_MAX -1);
dp[0] = 0;
for(int i = 0; i <= amount; ++i)
for(auto coin : coins)
if(i >= coin ) dp[i] = min(dp[i], dp[i- coin] + 1);
return dp[amount] == INT_MAX -1 ? -1 : dp[amount];
}
};
2. 递归
递归的方法效率要更高一些
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
int rec = INT_MAX;
sort(coins.begin(),coins.end(),greater<int>());
dfs(rec, coins, 0, 0, amount);
return rec == INT_MAX ? -1 : rec;
}
void dfs(int& rec, vector<int>& coins, int start, int count, int amount){
if(start >= coins.size())
return ;
if(amount % coins[start] == 0){
rec = min(rec, amount / coins[start] + count);
return ;
}
for(int i = amount / coins[start]; i >= 0; --i){
if(count + i >= rec -1) //如果条件成立,则后续的dfs所得到的值必然>= rec
break;
dfs(rec, coins, start + 1, count + i, amount - i * coins[start]);
}
return ;
}
};