第四章:零钱兑换问题——最少硬币组合
一、题目描述
给你一个整数数组
coins
,表示不同面额的硬币;另给一个整数amount
,表示总金额。请你计算并返回可以凑成总金额所需的最少硬币数量。如果没有任何一种硬币组合能组成总金额,返回 -1。
输入:coins = [1, 2, 5]
, amount = 11
输出:3
(11 = 5 + 5 + 1)
二、状态定义
令 dp[i]
表示凑出总金额为 i
所需的最少硬币数量。
三、状态转移方程
每个金额 i
可以由某个 i - coin
转移而来:
dp[i] = min(dp[i], dp[i - coin] + 1) for coin in coins 且 coin <= i
四、初始值
dp[0] = 0
(金额为 0 时不需要硬币)- 其他
dp[i]
初始化为正无穷大(或amount + 1
)
五、实现代码
function coinChange(coins, amount) {
const dp = new Array(amount + 1).fill(amount + 1);
dp[0] = 0;
for (let i = 1; i <= amount; i++) {
for (let coin of coins) {
if (i >= coin) {
dp[i] = Math.min(dp[i], dp[i - coin] + 1);
}
}
}
return dp[amount] === amount + 1 ? -1 : dp[amount];
}
- 时间复杂度:O(amount × coins.length)
- 空间复杂度:O(amount)
六、示例演算
输入:coins = [1, 2, 5]
, amount = 11
dp[0] = 0;
dp[1] = 1(1);
dp[2] = 1(2);
dp[3] = 2(1 + 2);
dp[4] = 2(2 + 2);
dp[5] = 1(5);
dp[6] = 2(5 + 1);
dp[7] = 2(5 + 2);
dp[8] = 3(5 + 2 + 1);
dp[9] = 3(5 + 2 + 2);
dp[10] = 2(5 + 5);
dp[11] = 3(5 + 5 + 1);
最终答案:3
七、小结
“零钱兑换问题”体现了完全背包模型中,每个物品可以无限次使用的特性。它进一步加强了我们对状态转移方程灵活构造能力的理解。
下一章我们将进入另一个热门题型——最长上升子序列(LIS),学习如何在序列上进行动态规划分析。