给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
你可以认为每种硬币的数量是无限的。
示例 1:
输入:coins = [1, 2, 5], amount = 11
输出:3
解释:11 = 5 + 5 + 1
示例 2:
输入:coins = [2], amount = 3
输出:-1
示例 3:
输入:coins = [1], amount = 0
输出:0
提示:
1 <= coins.length <= 121 <= coins[i] <= 231 - 10 <= amount <= 104
最初采用贪心算法,部分用例有问题,只是局部最优
严格来说,不能采用纯粹的贪心算法来保证解决所有的“零钱兑换”问题。
为什么纯贪心行不通?
贪心算法的核心是“每一步都做出当前看起来最好的选择”(即每次都拿最大面额的硬币)。这种方法只在特定的硬币面额体系下有效(比如我们现实生活中的人民币、美元体系:1, 2, 5, 10, 20, 50, 100)。
只要题目给出的硬币面额不满足这种特殊规律,贪心算法就会失效。
经典反例:coins = [1, 3, 4],amount = 6。
- 贪心:先拿 4,剩下 2 只能拿两个 1。结果:
4 + 1 + 1,共 3 枚。 - 最优:拿两个 3。结果:
3 + 3,共 2 枚。
var coinChange = function(coins, amount) {
if( amount===0) return 0;
if(coins.length <1) return 0;
coins.sort((a,b)=>b-a)
let num = 0;
const res = [];
let cur = coins.shift();
while(cur && amount>0 ){
if(amount >= cur){
amount = amount - cur;
console.log(cur,'cur')
res.push(cur);
}else{
cur = coins.length ? coins.shift() : 0;
}
}
console.log(res.length);
return amount===0 ? res.length :-1;
};
采用动态规划
var coinChange = function(coins, amount) {
const dp = new Array(amount+1).fill(Infinity);
dp[0] = 0;
for(let j=1; j<= amount; j++){
for(const c of coins){
if(j >= c){
dp[j] = Math.min(dp[j],dp[j-c]+1);
}
}
}
console.log(dp)
return dp[amount] === Infinity ? -1 : dp[amount];
};




