给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
示例 1:
输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1
示例 2:
输入: coins = [2], amount = 3
输出: -1
说明:
你可以认为每种硬币的数量是无限的。
来源:力扣(LeetCode)
搜索
对于这个题目,首先想到了暴力解决…使用逐个尝试的方法,遍历所有的可能,最后通过对比找出所需硬币数最小的一种情况。但是肯定超时。
class Solution {
int coinChange2(int index, vector<int>& coins, int amount) {
if (amount == 0) return 0;
if (index< coins.size() && amount > 0) {
int max_num= amount / coins[index];
int min_num = INT_MAX;
for (int x = 0; x <= max_num; x++) {
if (amount >= x * coins[index]) {
int res = coinChange2(index+ 1, coins, amount - x * coins[index]);
if (res != -1) min_num = min(min_num, res + x);
}
}
return min_num == INT_MAX ? -1: min_num;
}
return -1;
}
public:
int coinChange(vector<int>& coins, int amount) {
return coinChange2(0, coins, amount);
}
};
自下而上的动态规划
F ( i ) = m i n j = 0 , . . . n − 1 ( F ( i − c j ) + 1 ) F(i) = min_{j=0,...n-1}(F(i-c_j) + 1) F(i)=minj=0,...n−1(F(i−cj)+1)
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
int max = amount+1;
vector<int> v(max,max); // 定义一个数组,amount+1长度,每个元素初始值都为max
v[0]= 0;
for(int i=0;i<=amount;i++){
for(int j=0;j<coins.size();j++){
if(i-coins[j]>=0){
v[i] = min(v[i], v[i-coins[j]]+1);
}
}
}
// 因为初始为amount+1,若大于amount,说明没凑够
return v[amount]>amount?-1:v[amount];
}
};
自上而下
F ( i ) = m i n i = 0 , . . . , n − 1 F ( i − c i ) + 1 F(i) = min_{i=0,...,n-1}F(i-c_i) + 1 F(i)=mini=0,...,n−1F(i−ci)+1
public class Solution {
public int coinChange(int[] coins, int amount) {
if (amount < 1) return 0;
return coinChange(coins, amount, new int[amount]);
}
private int coinChange(int[] coins, int rem, int[] count) {
if (rem < 0) return -1;
if (rem == 0) return 0;
if (count[rem - 1] != 0) return count[rem - 1];
int min = Integer.MAX_VALUE;
for (int coin : coins) {
int res = coinChange(coins, rem - coin, count);
if (res >= 0 && res < min)
min = 1 + res;
}
count[rem - 1] = (min == Integer.MAX_VALUE) ? -1 : min;
return count[rem - 1];
}
}