详细运行思路
这段代码使用动态规划(Dynamic Programming, DP)解决最少硬币找零问题。
它的核心思想是:
状态转移方程:
dp[i] = min(dp[i], dp[i - coins[j]] + 1)
表示兑换 i 元最少需要的硬币数,取决于使用 coins[j] 后的最优解。
代码讲解
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
vector<int> dp(amount + 1, amount + 1); // 初始化 dp 数组,默认值为 amount+1(相当于无穷大)
dp[0] = 0; // 兑换 0 元需要 0 个硬币
for (int i = 1; i <= amount; i++) { // 遍历所有金额
for (int j = 0; j < coins.size(); j++) { // 遍历所有硬币
if (i >= coins[j]) { // 硬币 coins[j] 只能用于兑换大于等于它的金额
dp[i] = min(dp[i], dp[i - coins[j]] + 1); // 状态转移
}
}
}
return dp[amount] == (amount + 1) ? -1 : dp[amount]; // 返回结果
}
};
详细运行步骤
假设 coins = [1, 2, 5],amount = 11,来看代码如何执行。
初始化
vector<int> dp(amount + 1, amount + 1); // dp[0..11] 赋值为 amount+1(12)
dp[0] = 0; // 兑换 0 元需要 0 个硬币
初始 dp 数组:
dp[0] = 0
dp[1] = 12
dp[2] = 12
dp[3] = 12
dp[4] = 12
dp[5] = 12
dp[6] = 12
dp[7] = 12
dp[8] = 12
dp[9] = 12
dp[10] = 12
dp[11] = 12
第一层循环:遍历金额
i = 1
遍历硬币:
• 硬币 1:可以兑换 1 元,dp[1] = min(dp[1], dp[1-1] + 1) = min(12, 0 + 1) = 1
• 硬币 2:无法兑换 1 元(跳过)
• 硬币 5:无法兑换 1 元(跳过)
更新 dp[1] = 1
dp[0] = 0
dp[1] = 1
dp[2] = 12
dp[3] = 12
dp[4] = 12
dp[5] = 12
dp[6] = 12
dp[7] = 12
dp[8] = 12
dp[9] = 12
dp[10] = 12
dp[11] = 12
i = 2
遍历硬币:
• 硬币 1:dp[2] = min(dp[2], dp[2-1] + 1) = min(12, 1 + 1) = 2
• 硬币 2:dp[2] = min(dp[2], dp[2-2] + 1) = min(2, 0 + 1) = 1
• 硬币 5:无法兑换 2 元(跳过)
更新 dp[2] = 1
dp[0] = 0
dp[1] = 1
dp[2] = 1
dp[3] = 12
dp[4] = 12
dp[5] = 12
dp[6] = 12
dp[7] = 12
dp[8] = 12
dp[9] = 12
dp[10] = 12
dp[11] = 12
i = 3
遍历硬币:
• 硬币 1:dp[3] = min(dp[3], dp[3-1] + 1) = min(12, 1 + 1) = 2
• 硬币 2:dp[3] = min(dp[3], dp[3-2] + 1) = min(2, 1 + 1) = 2
• 硬币 5:无法兑换 3 元(跳过)
更新 dp[3] = 2
dp[0] = 0
dp[1] = 1
dp[2] = 1
dp[3] = 2
dp[4] = 12
dp[5] = 12
dp[6] = 12
dp[7] = 12
dp[8] = 12
dp[9] = 12
dp[10] = 12
dp[11] = 12
i = 4
遍历硬币:
• 硬币 1:dp[4] = min(dp[4], dp[4-1] + 1) = min(12, 2 + 1) = 3
• 硬币 2:dp[4] = min(dp[4], dp[4-2] + 1) = min(3, 1 + 1) = 2
• 硬币 5:无法兑换 4 元(跳过)
更新 dp[4] = 2
dp[0] = 0
dp[1] = 1
dp[2] = 1
dp[3] = 2
dp[4] = 2
dp[5] = 12
dp[6] = 12
dp[7] = 12
dp[8] = 12
dp[9] = 12
dp[10] = 12
dp[11] = 12
继续计算 dp[5] 到 dp[11],最终得到:
dp[0] = 0
dp[1] = 1
dp[2] = 1
dp[3] = 2
dp[4] = 2
dp[5] = 1
dp[6] = 2
dp[7] = 2
dp[8] = 3
dp[9] = 3
dp[10] = 2
dp[11] = 3
最终结果
return dp[amount] == (amount + 1) ? -1 : dp[amount];
• dp[11] = 3
• 所以最少需要 3 枚硬币兑换 11(可能的组合:5 + 5 + 1)
总结
• 时间复杂度:O(n × m)(n 是 amount,m 是 coins.size())
• 空间复杂度:O(n)(dp 数组)