原文地址: http://www.iming.top/details/5
给你 k 种面值的硬币,面值分别为 c1, c2 ... ck,每种硬币的数量无限
再给一个总金额 amount,问你最少需要几枚硬币凑出这个金额,如果不可能凑出,算法返回 -1 。
function coinChange(coins, amount) {
const dp = []
for (let i = 0; i <= amount; i++) {
dp.push(Infinity)
}
dp[0] = 0
for (let i = 1; i <= amount; i++) {
for (let j = 0; j < coins.length; j++) {
if (coins[j] > i) continue;
const a = dp[i - coins[j]] + 1
dp[i] = Math.min(dp[i], a)
}
}
return dp[amount] === Infinity ? -1 : dp[amount]
}
console.log(coinChange([1,2,5] , 11))
分析如下:
想要凑够钱,使用最少的硬币,这里定义了一个数组
dp = [ Infinity,Infinity,Infinity,Infinity,Infinity,... ]
数组每一位都是无穷大,其实是占个位置,如果书其他的,最好还是number类型,因为后面使用了Math.min()函数
假设
coins = [1,2,5], amount = 11
如果在所选择的硬币当中含有1,那么总次数应该是 1 + dp(10)的最优解 如果在所选择的硬币当中含有2,那么总次数应该是 1 + dp(9)的最优解 如果在所选择的硬币当中含有5,那么总次数应该是 1 + dp(6)的最优解
问题就在组这里, 这时候我们不知道dp(10), dp(9)和dp(6)的最优解是什么
于是对于dp(10)来说:
如果在所选择的硬币当中含有1,那么总次数应该是 1 + dp(9)的最优解 如果在所选择的硬币当中含有2,那么总次数应该是 1 + dp(8)的最优解 如果在所选择的硬币当中含有5,那么总次数应该是 1 + dp(5)的最优解
以此类推,直到dp(0) 负数不考虑。而且dp里面是负数不会对数组造影响,因此我们只考虑到最后一个是dp(0)的情况
由上面的推断就可以得出来,我们需要求出0-amount每一位的最优值,因此有:
for (let i = 1; i <= amount; i++) { // 循环1-amount for (let j = 0; j < coins.length; j++) { // 看看选择不同的硬币后对比那个才是使用最少次数的。决定本轮的硬币的选择。 if (coins[j] > i) continue; const a = dp[i - coins[j]] + 1 dp[i] = Math.min(dp[i], a) } }
最终得到结果dp[amount]