题目描述:给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
动态规划解决方案
const coinChange = function(coins, amount) {
// 用于保存每个目标总额对应的最小硬币个数
const f = []
// 提前定义已知情况
f[0] = 0
// 遍历 [1, amount] 这个区间的硬币总额
for(let i=1;i<=amount;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)
}
}
}
// 若目标总额对应的解为无穷大,则意味着没有一个符合条件的硬币总数来更新它,本题无解,返回-1
if(f[amount]===Infinity) {
return -1
}
// 若有解,直接返回解的内容
return f[amount]
};
}
拍平代码来理解代码实现
输入[1,2,5]和总额11
- 总额为1时,最少需要几个硬币?
- f[1]=f[0]+1* 1元硬币
f[1]=f[0]+1* 2元硬币因为一元不可能由2元硬币组成,不用考虑(也就是不会走到 if (i - coins[c] >= 0) 这里)f[1]=f[0]+1* 5元硬币因为一元不可能由5元硬币组成,不用考虑
- 总额为2时,最少需要几个硬币?
- f[2]=f[1]+1* 1元硬币 f[1]已经在前面算出最少为1,所以f[2]=1+1=2枚
- f[2]=f[0]+1* 2元硬币 需要1枚
f[2]=f[0]+1*5元硬币2元不可能由5元硬币组成,不考虑
- 总额为3时,最少需要几个硬币?
- f[3]=f[2]+1* 1元硬币 f[2]已经在前面算出最少为1枚,所以f[3]=1+1=2枚
- f[3]=f[1]+1* 2元硬币 f[1]已经在前面算出最少为1枚,所以f[3]=1+1=2枚
f[3]=f[0]+1*5元硬币3元不可能由5元硬币组成,不考虑
- 省略
- 总额为5时,最少需要几个硬币?
- f[5]=f[4]+1* 1元硬币 f[4]已经在前面算出最少为2枚,所以f[4]=2+1=3枚
- f[5]=f[3]+1* 2元硬币 f[3]已经在前面算出最少为2枚,所以f[3]=1+1=3枚
- f[5]=f[0]+1* 5元硬币 f[0]已经在前面算出最少为0枚,所以f[5]=0+1=1枚
- 省略
- 以此类推 总额为11的时候,至少需要多少硬币呢?
- f[11]=f[10]+1个* 1元硬币 f[10]之前算出是最少需要2枚 所以此种方案需要3枚
- f[11]=f[9]+1个* 2元硬币 f[9]之前算出是最少需要3枚 所以此种方案需要4枚
- f[11]=f[6]+1个* 5元硬币 f[6]之前算出是最少需要2枚 所以此种方案需要3枚
所以最后至少需要3枚硬币