1,题目要求
You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.
Example 1:
Input: coins = [1, 2, 5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1
Example 2:
Input: coins = [2], amount = 3
Output: -1
Note:
You may assume that you have an infinite number of each kind of coin.
您将获得不同面额的硬币和总金额。 编写一个函数来计算构成该数量所需的最少数量的硬币。 如果这笔钱不能由任何硬币组合弥补,则返回-1。
2,题目思路
对于这道题,给定硬币的的面值种类和总的金额目标,求出最小的硬币数。
对于这个问题而言,经过分析我们可以得知,使用动态规划是一个可行的策略。
这里,我们可以定义DP[i]
为总金额加和等于i的所需要的硬币的数目。
于是,我们有:
DP[i] = min(DP[i], DP[i - coins[j]] + 1);
不过,动态规划的策略运行时间较慢,这里,还有另外一种方法:将硬币按照面值从大到小的顺序进行排序,然后,利用递归的方法逐个进行尝试。
3,代码实现
1,动态规划
int x = []() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
return 0;
}();
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
int MAX = amount + 1;
vector<int> DP (amount+1, MAX);
DP[0] = 0;
for(int i = 1;i<=amount;i++)
for(int j = 0;j < coins.size();j++)
if(coins[j] <= i)
DP[i] = min(DP[i], DP[i - coins[j]] + 1);
if(DP[amount] > amount)
return -1;
else
return DP[amount];
}
};
2,对coin按照面值排序,递归查找
int x = []() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
return 0;
}();
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
//按从大到小的顺序对coin面值进行排序
sort(coins.rbegin(), coins.rend());
int ans = amount+1;
coinHelper(coins, amount, 0, 0, ans);
return ans == amount + 1? -1 : ans;
}
private:
//idx为遍历到coins的下标,curr为当前的总coin数
void coinHelper(vector<int>& coins, int amount, int idx, int curr, int& ans){
if(amount == 0){
ans = min(ans, curr);//找到了一个解,没必要再继续 (再往下只会coins数增多)
return;
}
// coins枚举完毕,amount仍然 > 0,此组合不可行
if (idx == coins.size()) return;
// combination for coin: 0 ~ amount/coin
const int coin = coins[idx];
//coin面值从大到小,所以这样是可行的
for(int i = amount/coin;i>=0 && curr+i<ans;i--)
coinHelper(coins, amount-i*coin, idx+1, curr + i, ans);
}
};