#问题: 给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
你可以认为每种硬币的数量是无限的。
这是一道经典的最值问题,我们可以直接暴力破解使用穷举法,但很明显在这道题中coins的不确定性使得穷举法难以实现。所以我们不妨转变思路采用递归的方式来尝试解决,就像算法题爬楼梯一样。请看以下代码
const coinChange = function (coins, amount) {
// 递归终止条件
if (amount === 0) {
return 0;
}
if (amount < 0) {
return -1;
}
let minCount = Infinity;
for (let i = 0; i < coins.length; i++) {
let subproblem = coinChange(coins, amount - coins[i]);
// 子问题无解,跳过
if (subproblem === -1) {
continue;
}
minCount = Math.min(minCount, subproblem + 1);
}
return minCount === Infinity ? -1 : minCount;
}
console.log(coinChange([9, 1], 22));
在这段代码中,定义了一个递归函数coinChange,接受硬币面额数组coins和目标金额amount作为参数。
首先,设定递归的终止条件:当目标金额为0时,不需要任何硬币,返回0;当目标金额小于0时,无法凑成目标金额,返回-1。
然后,遍历硬币面额数组coins,对于每个硬币面额,递归调用coinChange函数,传入减去当前硬币面额后的目标金额。如果返回的子问题结果不为-1(即有解),则将子问题结果加1,并与之前的最小硬币数量进行比较,更新最小值。
最后,如果最小硬币数量仍然是初始值Infinity,则表示无法凑成目标金额,返回-1;否则返回最小硬币数量。
在给定的例子中,输入为[9, 1]和22,表示有两种面额的硬币分别为9和1,需要凑成金额22。根据代码计算,最少需要3个硬币,所以输出结果为3。
需要注意的是,使用递归方法解决问题时,可能会导致重复计算,效率较低。
正如图中展示的,虽然测用实例以及测试结果没有问题,但当
amount的数值过大其运行时的重复计算会大大耗费时间导致效率极低,我们可以看到在力扣中提交已经超出了时间限制。
这时候我们最好转变思路,既然递归的方法可以实现,那么我们为什么不能使用动态规划来解决重复计算效率低的情况呢?请和我一起看向下面的代码:
const coinChange = function (coins, amount) {
const f = []; // f[11] = 3
f[0] = 0;
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)
}
}
}
if (f[amount] === Infinity) {
return - 1
}
return f[amount]
}
console.log(coinChange([9,1],22))
在这段代码中,定义了一个递归函数coinChange,接受硬币面额数组coins和目标金额amount作为参数。
而后定义了一个数组f,用于存储凑成各个金额所需的最少硬币数量。初始化f[0]为0,表示凑成金额为0时不需要任何硬币。
然后使用两层循环遍历每个金额i(从1到amount),内层循环遍历硬币面额coins[j],如果当前金额i减去硬币面额coins[j]仍然大于等于0,说明可以使用coins[j]硬币来凑成金额i,此时更新f[i]的值为f[i - coins[j]] + 1和当前f[i]的较小值。
最后,如果f[amount]仍然是初始值Infinity,则表示无法凑成指定金额,返回-1;否则返回f[amount],即所需的最少硬币数量。
在给定的例子中,输入为[9, 1]和22,表示有两种面额的硬币分别为9和1,需要凑成金额22。根据代码计算,最少需要3个硬币,所以输出结果为3。
总结: 递归是一种强大的工具,可以解决许多问题,而当面临重复计算会大大耗费时间导致效率极低等问题时可以及时转变思路采用动态规划的方法可以有效解决。总之无论什么方法,高效简便的解决问题才是我们需要的。希望这篇文章可以帮助你扩展思路,对你的算法有所提升。