【力扣100题】45.零钱兑换

题目描述

给定一个整数数组 coins(不同面额的硬币)以及一个整数 amount(总金额),计算并返回凑成总金额所需的最少硬币个数 。如果没有任何硬币组合能组成总金额,返回 -1

可以认为每种硬币的数量是无限的。

示例:

  • 输入:coins = [1, 2, 5], amount = 11 → 输出:311 = 5 + 5 + 1
  • 输入:coins = [2], amount = 3 → 输出:-1
  • 输入:coins = [1], amount = 0 → 输出:0

解题思路总览

方法 思路 时间复杂度 空间复杂度
动态规划 dp[i] 表示凑成金额 i 的最少硬币数,状态转移 dp[i] = min(dp[i], dp[i-coin]+1) O(amount × len(coins)) O(amount)
BFS 从金额 0 出发,每次加上一种硬币,求最少步数 O(amount × len(coins)) O(amount)

本题采用**动态规划(完全背包)**方法。


完整代码

cpp 复制代码
class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        vector<int> dp(amount + 1, amount + 1);
        int n = coins.size();
        dp[0] = 0;
        for (int i = 1; i <= amount; i++) {
            for (int j = 0; j < n; j++) {
                if (coins[j] <= i) {
                    dp[i] = min(dp[i], dp[i - coins[j]] + 1);
                }
            }
        }
        return dp[amount] == amount + 1 ? -1 : dp[amount];
    }
};

算法流程图

复制代码
输入: coins = [1, 2, 5], amount = 11

初始化:
  dp[0] = 0
  dp[1...11] = amount+1 = 12 (表示正无穷,即无法凑成)

i = 1:
  j = 0, coin = 1 <= 1
    dp[1] = min(12, dp[0]+1) = 1
  j = 1, coin = 2 > 1, 跳过
  j = 2, coin = 5 > 1, 跳过
  dp[1] = 1

i = 2:
  j = 0, coin = 1 <= 2
    dp[2] = min(12, dp[1]+1) = 2
  j = 1, coin = 2 <= 2
    dp[2] = min(2, dp[0]+1) = 1
  j = 2, coin = 5 > 2, 跳过
  dp[2] = 1

i = 3:
  j = 0, coin = 1 <= 3
    dp[3] = min(12, dp[2]+1) = 2
  j = 1, coin = 2 <= 3
    dp[3] = min(2, dp[1]+1) = 2
  j = 2, coin = 5 > 3, 跳过
  dp[3] = 2

i = 4:
  j = 0, coin = 1 <= 4
    dp[4] = min(12, dp[3]+1) = 3
  j = 1, coin = 2 <= 4
    dp[4] = min(3, dp[2]+1) = 2
  j = 2, coin = 5 > 4, 跳过
  dp[4] = 2

i = 5:
  j = 0, coin = 1 <= 5
    dp[5] = min(12, dp[4]+1) = 3
  j = 1, coin = 2 <= 5
    dp[5] = min(3, dp[3]+1) = 3
  j = 2, coin = 5 <= 5
    dp[5] = min(3, dp[0]+1) = 1
  dp[5] = 1

... (继续迭代直到 i = 11)

i = 11:
  j = 0, coin = 1 <= 11
    dp[11] = min(12, dp[10]+1)
  j = 1, coin = 2 <= 11
    dp[11] = min(dp[11], dp[9]+1)
  j = 2, coin = 5 <= 11
    dp[11] = min(dp[11], dp[6]+1) = 3

最终 dp[11] = 3
输出: 3

逐行解析

cpp 复制代码
vector<int> dp(amount + 1, amount + 1);

含义: 创建大小为 amount+1 的数组,dp[i] 表示凑成金额 i 的最少硬币数。初始化为 amount+1 作为"正无穷",因为凑成 amount 最多需要 amount 个 1 元硬币,所以 amount+1 一定大于任何可行解。

cpp 复制代码
int n = coins.size();

含义: 记录硬币种类数量,方便后续循环使用。

cpp 复制代码
dp[0] = 0;

含义: 基础情况,凑成金额 0 需要 0 个硬币。

cpp 复制代码
for (int i = 1; i <= amount; i++)

含义: 从金额 1 到 amount 依次计算每个金额的最少硬币数。

cpp 复制代码
for (int j = 0; j < n; j++)

含义: 遍历所有硬币面额,尝试用每种硬币来凑当前金额。

cpp 复制代码
if (coins[j] <= i)

含义: 只有当硬币面额不超过当前要凑的金额 i 时,才能使用这枚硬币(因为不能有负数)。

cpp 复制代码
dp[i] = min(dp[i], dp[i - coins[j]] + 1);

含义: 状态转移方程。如果使用面额为 coins[j] 的硬币,那么剩下的 i-coins[j] 金额需要 dp[i-coins[j]] 个硬币,再加上当前的 1 枚硬币,总共 dp[i-coins[j]]+1 个。取较小值更新 dp[i]

cpp 复制代码
return dp[amount] == amount + 1 ? -1 : dp[amount];

含义: 如果 dp[amount] 仍然是初始值 amount+1,说明没有任何硬币组合能凑成 amount,返回 -1;否则返回实际计算出的最少硬币数。


复杂度分析

复杂度 说明
时间复杂度 O(amount × len(coins)) 外层循环 amount 次,内层循环 len(coins) 次
空间复杂度 O(amount) 需要大小为 amount+1 的 dp 数组

面试追问 FAQ

问题 答案
为什么初始化为 amount+1 而不是 INT_MAX 因为 INT_MAX 参与 dp[i-coins[j]]+1 计算时会溢出,而 amount+1 既足够大又不会溢出
完全背包和 0-1 背包的区别? 0-1 背包每种物品只能用一次,内层循环倒序;完全背包每种物品无限使用,内层循环正序
如何输出具体硬币组合? 额外记录每个状态是从哪个硬币转移来的,最后回溯即可
如果要求硬币组合数最少怎么办? 使用 dp[i] += dp[i-coin] 而不是 min,统计组合个数
amount = 0 时返回什么? 返回 0,因为不需要任何硬币就能凑成 0 元

相关题目

题号 题目 难度 核心思路
322 零钱兑换 中等 完全背包
279 完全平方数 中等 动态规划
518 零钱兑换 II 中等 完全背包(组合数)
416 分割等和子集 中等 0-1 背包

总结

要点 内容
核心思想 完全背包动态规划,枚举所有硬币作为最后一个加数
状态定义 dp[i] = 凑成金额 i 的最少硬币数
状态转移 dp[i] = min(dp[i], dp[i-coin]+1)
初始化 dp[0] = 0,其他为 amount+1(正无穷)
返回值 dp[amount] == amount+1 ? -1 : dp[amount]

相关推荐
alphaTao1 小时前
LeetCode 每日一题 2026/5/11-2026/5/17
算法·leetcode
Aaron15882 小时前
全频段 SDR干扰源模块解决方案(星链干扰、LORA无人机干扰)
人工智能·算法·fpga开发·硬件架构·硬件工程·无人机·信息与通信
AI科技星2 小时前
全域数学·球面拓扑微扰标准系数η=0.01 应用详解(典籍正式版)
人工智能·算法·数学建模·数据挖掘·机器人
芝士爱知识a2 小时前
2026 年教资面试考前急救软件推荐:基于智蛙面试app的技术评测
面试·职场和发展·智蛙面试·教资面试软件·ai模拟面试·教资考前急救·多模态大模型应用
逻辑君2 小时前
物理学研究报告【20260001】
人工智能·算法
YL200404262 小时前
041二叉树的层序遍历
数据结构·leetcode·bfs
AI科技星2 小时前
算法联盟·全域数学公理体系下黑洞标量毛发与LVK引力波O4全维理论、求导、证明、计算、验证、分析
人工智能·线性代数·算法·架构·学习方法·量子计算
谙弆悕博士2 小时前
【附C语言源码】C语言 栈结构 实现及其扩展操作
c语言·开发语言·数据结构·算法·链表·指针·
YuanDaima20482 小时前
图论基础原理与题目说明
数据结构·人工智能·python·算法·图论·手撕代码