leetcode 322零钱兑换

一、完整代码(精简注释)

复制代码
class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        // dp[i]:凑出金额 i 所需的最少硬币数
        vector<int> dp(amount + 1, amount + 1);
        dp[0] = 0;  // 凑出0元需要0枚硬币

        for (int i = 1; i <= amount; i++) {
            for (int j = 0; j < coins.size(); j++) {
                if (coins[j] <= i) { // 当前硬币不能超过金额i
                    // 选择当前硬币,更新最少硬币数
                    dp[i] = min(dp[i], dp[i - coins[j]] + 1);
                }
            }
        }

        // 无法凑出返回-1,否则返回最少硬币数
        return dp[amount] > amount ? -1 : dp[amount];
    }
};

二、动态规划五步总结

1. 确定 dp 数组含义

dp[i] 表示凑出金额 i 所需要的最少硬币数量。

最终目标是求 dp[amount]。

2. 确定状态转移方程

\ \\boxed{dp\[i=\min(dpi,dpi-coins\[j]+1)} \]

  • dp[i]:当前凑出金额 i 的最少硬币数。

  • dp[i-coins[j]]:凑出剩余金额需要的最少硬币数。

  • +1:加上当前选择的这枚硬币。

  • min():在所有硬币选择中取最优解。

例如 coins = [1,2,5],计算 dp[6]:

复制代码
选择1元:dp[5] + 1 = 2
选择2元:dp[4] + 1 = 3
选择5元:dp[1] + 1 = 2

dp[6] = min(2,3,2) = 2

3. 初始化 dp 数组

复制代码
vector<int> dp(amount + 1, amount + 1);
dp[0] = 0;
  • 第一个 amount+1:数组长度,包含 dp[0] 到 dp[amount]。

  • 第二个 amount+1:初始化为一个不可能的较大值,表示暂时无法凑出。

  • dp[0]=0:凑出金额 0 不需要硬币。

这里用 amount+1 代替 INT_MAX,既能表示无解,又能避免状态转移时整数溢出。

4. 确定遍历顺序

复制代码
for (int i = 1; i <= amount; i++) {
    for (int j = 0; j < coins.size(); j++) {
        if (coins[j] <= i) {
            dp[i] = min(dp[i], dp[i - coins[j]] + 1);
        }
    }
}
  • 外层循环:从小金额到大金额,保证计算当前状态时,之前的小金额已经计算完成。

  • 内层循环:遍历所有硬币,寻找最少硬币数量。

  • coins[j] <= i:防止 i-coins[j] 为负数,导致数组越界。

由于每种硬币可以无限使用,因此同一枚硬币可以在不同状态转移中重复选择。

5. 确定返回值

复制代码
return dp[amount] > amount ? -1 : dp[amount];
  • 如果 dp[amount] > amount,说明无法凑出,返回 -1。

  • 否则返回最少硬币数量。

三、复杂度分析

设 n 为硬币种类数。

  • 时间复杂度: \(O(amount \times n)\),每个金额都需要遍历所有硬币。

  • 空间复杂度: \(O(amount)\),使用一维 dp 数组存储结果。

四、核心思路总结

这道题属于完全背包问题中的求最小值问题,因为每种硬币可以无限次使用。

核心思想是:

要求凑出金额 i 的最少硬币数,就枚举最后选择的硬币,利用剩余金额的最优解,再加上当前这枚硬币。

记住三个关键点:

  1. dp[i] 存储的是凑出金额 i 的最优解,而不是具体硬币组合。

  2. dp[i-coins[j]]+1 表示选择一枚当前硬币后的总数量。

  3. amount+1 作为无解标记,是这道题初始化的关键技巧。

这与之前做的「完全平方数」是同一种动态规划思路,只不过一个枚举硬币面值,一个枚举完全平方数。

相关推荐
傅科摆 _ py16 小时前
DP,贪心,堆和栈,二分力扣复习
开发语言·python·算法
Shaoshing16 小时前
LeetCode100 42.接雨水
java·算法·leetcode
域限奇点访客16 小时前
用AI生成问卷的网站怎么选?看题目录入结构、题型映射和生成后的校验
算法
soft_hub117 小时前
海外会议怎么用录音APP翻译会议内容
面试·职场和发展
文丑颜不良啊17 小时前
LeetCode1261~1280题目解析
java·leetcode
not coder17 小时前
一文讲通--从树到红黑树
数据结构·算法
octopus_c17 小时前
C++ 入门
开发语言·c++·算法
ZhengEnCi18 小时前
2026年10月30日AI早报:Gemini 4 Carbon登顶、DeepSeek融资1055亿、智元机器人上岗实测
人工智能·算法
强哥聊算力18 小时前
《算力江湖·Intel帝国往事》第三集:安迪·格鲁夫的铁血时代:Intel为什么能把对手逼到墙角?
运维·人工智能·科技·算法·ai·gpu算力
Shaoshing18 小时前
LeetCode100 11. 盛最多水的容器
算法·leetcode