中等
题目
给定不同面额的硬币 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
示例 4:
输入: coins = [1], amount = 1
输出: 1
示例 5:
输入: coins = [1], amount = 2
输出: 2
提示:
1 <= coins.length <= 121 <= coins[i] <= 231 - 10 <= amount <= 104
给出动态规划的代码方法:
var coinChange = function(coins, amount) {
const f=[]
f[0]=0
for(let i=1;i<=amount;i++){
//f[i]
f[i]=Infinity; //先设置成最大值
for(let j=0 ;j<coins.length;j++){
if(i - coins[j]>=0){
f[i]=Math.min(f[i],f[i - coins[j]]+1)//我的leetcode函数总结文章有提到这个方法
}
}
}
if(f[amount]===Infinity){
return -1
}
return f[amount]
};
//循环示例
i=1 f[1]=Math.min(Infinity,1) f[1]=1
i=2 j=0 f[2]=Math.min(Infinity,2) f[2]=2
j=1 f[2]=Math.min(f[2]=2,1) f[2]=1 f[2]取最小值
i=3 j=0 f[3]=Math.min( Infinity,2) f[3]=2
i=3 j=1 f[3]=Math.min( f[3]=2,2) f[3]= 2
这是一个使用动态规划思想解决硬币找零问题的函数,其中:
- coins 是一个整数数组,表示不同面额的硬币;
- amount 是需要找零的总钱数。
该函数通过循环遍历 1 到 amount 的范围,对于每个 i,都尝试用所有可用的硬币进行找零。在找零过程中,该函数使用一个数组 f 来记录当前总钱数为 i 时所需的最小硬币数量。
具体实现中,f[i] 初始值设为 Infinity,表示当前还没有任何一种硬币可以组成总钱数为 i。接着,对于每个 j 在硬币数组 coins 中,如果当前总钱数 i 减去硬币面额 coins[j] 的差值大于等于 0,那么就可以考虑把一个面额为 coins[j] 的硬币加入到当前的找零方案中,此时需要用 f[i-coins[j]] 表示从总钱数为 i-coins[j] 的状态转移而来,因为加入了一枚面额为 coins[j] 的硬币。因此,更新 f[i] 的值时,只需要比较 f[i] 和 f[i-coins[j]]+1 两者的大小关系,取其中的较小值即可。
最后,如果 f[amount] 的值仍然为 Infinity,说明无法找零成功,此时函数返回 -1,否则返回 f[amount] 的值,表示总钱数为 amount 时所需的最小硬币数量。
这个算法的时间复杂度为O(amount * coins.length),空间复杂度为O(amount)。