LeetCode Hot100(70/100)—— 322. 零钱兑换

前端JavaScript力扣HOT100刷题【51-100】 注:纯手打,如有错误欢迎评论区交流!编写此文是为了更好地学习前端知识,如果损害了有关人的利益,请联系删除!本文章将不定时更新,敬请期待!!!!! 阅读详情

题目链接

LeetCode 322. 零钱兑换

题目描述

给你一个整数数组 coins,表示不同面额的硬币;以及一个整数 amount,表示总金额。

计算并返回可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。

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

示例 1:

输入:coins = [1, 2, 5], amount = 11
输出:3 
解释:11 = 5 + 5 + 1

示例 2:

输入:coins = [2], amount = 3
输出:-1

示例 3:

输入:coins = [1], amount = 0
输出:0

提示:

  • 1 <= coins.length <= 12
  • 1 <= coins[i] <= 2^31 - 1
  • 0 <= amount <= 10^4

问题分析

零钱兑换

问题特征

完全背包问题

求最优解

硬币可重复使用

解决思路

动态规划

自底向上

状态转移

贪心算法

不适用

反例存在

BFS搜索

层序遍历

找最短路径

关键点

状态定义

转移方程

初始化

边界处理

这是一个经典的完全背包问题,核心在于:

  • 每种硬币可以使用无限次
  • 需要找到凑成目标金额的最少硬币数
  • 如果无法凑成,返回 -1

解法一:动态规划(自底向上)

算法原理

动态规划是解决此问题的最优方法。我们定义状态 dp[i] 表示凑成金额 i 所需的最少硬币数。

状态转移方程:

dp[i] = min(dp[i], dp[i - coin] + 1)

其中 coin 是硬币面额,i - coin >= 0。

思路流程:

是

否

否

是

否

是

是

否

开始

初始化 dp 数组

dp0 = 0, 其余为无穷大

遍历金额 i = 1 到 amount

遍历每个硬币 coin

i >= coin?

更新 dp[i] = min(dp[i], dp[i-coin]+1)

所有硬币遍历完?

所有金额遍历完?

dp[amount] == 无穷大?

返回 -1

返回 dp[amount]

结束

Java 实现

class Solution {
    public int coinChange(int[] coins, int amount) {
        // dp[i] 表示凑成金额 i 所需的最少硬币数
        int[] dp = new int[amount + 1];
        
        // 初始化:除了 dp[0] = 0,其余都设为一个不可能的大值
        Arrays.fill(dp, amount + 1);
        dp[0] = 0;
        
        // 遍历每个金额
        for (int i = 1; i <= amount; i++) {
            // 尝试每种硬币
            for (int coin : coins) {
                // 如果当前硬币面额不大于当前金额
                if (coin <= i) {
                    // 状态转移:选择使用当前硬币或不使用
                    dp[i] = Math.min(dp[i], dp[i - coin] + 1);
                }
            }
        }
        
        // 如果 dp[amount] 仍然是初始值,说明无法凑成
        return dp[amount] > amount ? -1 : dp[amount];
    }
}

复杂度分析

  • 时间复杂度: O(amount × n),其中 n 是硬币种类数。需要计算 amount 个状态,每个状态需要遍历所有硬币。
  • 空间复杂度: O(amount),需要一个长度为 amount + 1 的 dp 数组。

示例演示

以 coins = [1, 2, 5], amount = 11 为例:

金额 idp[i]计算过程
00初始值
11min(∞, dp[0]+1) = 1
21min(∞, dp[1]+1, dp[0]+1) = 1
32min(∞, dp[2]+1, dp[1]+1) = 2
42min(∞, dp[3]+1, dp[2]+1) = 2
51min(∞, dp[4]+1, dp[3]+1, dp[0]+1) = 1
………
113dp[10]+1 或 dp[6]+1 = 3

解法二:动态规划(记忆化搜索)

算法原理

记忆化搜索是自顶向下的动态规划方法,通过递归实现,并使用备忘录避免重复计算。

递归思路:

  • 对于金额 amount,尝试使用每种硬币
  • 递归计算 amount - coin 的最少硬币数
  • 取所有可能中的最小值

coinChange 11

尝试硬币1

尝试硬币2

尝试硬币5

coinChange 10

coinChange 9

coinChange 6

coinChange 5

coinChange 4

coinChange 1

Java 实现

class Solution {
    private int[] memo;
    
    public int coinChange(int[] coins, int amount) {
        memo = new int[amount + 1];
        Arrays.fill(memo, -2); // -2 表示未计算,-1 表示无解
        return dfs(coins, amount);
    }
    
    private int dfs(int[] coins, int amount) {
        // 基础情况
        if (amount == 0) return 0;
        if (amount < 0) return -1;
        
        // 如果已经计算过,直接返回
        if (memo[amount] != -2) {
            return memo[amount];
        }
        
        int minCoins = Integer.MAX_VALUE;
        
        // 尝试每种硬币
        for (int coin : coins) {
            int subResult = dfs(coins, amount - coin);
            // 如果子问题有解
            if (subResult >= 0) {
                minCoins = Math.min(minCoins, subResult + 1);
            }
        }
        
        // 记录结果
        memo[amount] = (minCoins == Integer.MAX_VALUE) ? -1 : minCoins;
        return memo[amount];
    }
}

复杂度分析

  • 时间复杂度: O(amount × n),每个状态只计算一次,每次需要遍历所有硬币。
  • 空间复杂度: O(amount),需要备忘录数组和递归调用栈空间。

解法三:BFS 广度优先搜索

算法原理

将问题看作图的最短路径问题:

  • 起点是金额 0
  • 终点是目标金额 amount
  • 每次可以选择一种硬币,相当于图中的一条边
  • 求从起点到终点的最短路径

+1

+2

+5

+1

+2

+5

+1

+2

+5

0

1

2

5

2

3

6

3

4

7

Java 实现

class Solution {
    public int coinChange(int[] coins, int amount) {
        if (amount == 0) return 0;
        
        Queue<Integer> queue = new LinkedList<>();
        boolean[] visited = new boolean[amount + 1];
        
        queue.offer(0);
        visited[0] = true;
        int step = 0;
        
        while (!queue.isEmpty()) {
            int size = queue.size();
            step++;
            
            // 处理当前层的所有节点
            for (int i = 0; i < size; i++) {
                int current = queue.poll();
                
                // 尝试每种硬币
                for (int coin : coins) {
                    int next = current + coin;
                    
                    // 找到目标金额
                    if (next == amount) {
                        return step;
                    }
                    
                    // 如果未访问且未超过目标金额
                    if (next < amount && !visited[next]) {
                        visited[next] = true;
                        queue.offer(next);
                    }
                }
            }
        }
        
        return -1;
    }
}

复杂度分析

  • 时间复杂度: O(amount × n),最坏情况下需要访问所有金额状态。
  • 空间复杂度: O(amount),需要队列和访问标记数组。

解法对比分析

解法时间复杂度空间复杂度实现难度性能表现适用场景
动态规划(自底向上)O(amount × n)O(amount)⭐⭐⭐最优通用场景,推荐使用
动态规划(记忆化搜索)O(amount × n)O(amount)⭐⭐⭐⭐良好递归思维更直观
BFS 广度优先搜索O(amount × n)O(amount)⭐⭐⭐⭐良好理解最短路径问题

性能对比说明

  1. 动态规划(自底向上) 是最推荐的解法:

    • 代码简洁清晰
    • 无递归开销
    • 空间利用率高
    • 适合大规模数据
  2. 记忆化搜索 适合递归思维:

    • 代码逻辑更直观
    • 有递归调用栈开销
    • 适合理解问题本质
  3. BFS 搜索 提供不同视角:

    • 将问题转化为图论
    • 层序遍历保证最优解
    • 队列操作有额外开销
    • 适合理解最短路径思想

零钱兑换问题是完全背包问题的经典应用,核心在于理解状态转移方程。动态规划自底向上的方法是最优解,时间和空间复杂度都达到了理论最优。掌握这道题的解法,对理解动态规划和完全背包问题有重要意义。

leetCode-hot100-动态规划专题 阅读详情

相关推荐

Leetcode hot100刷题指南:算法进阶与面试突破

算法作为计算机科学的核心基础,其重要性体现在从数据结构优化到系统设计的各个层面。动态规划和二叉树遍历等经典算法通过特定的问题解决范式(如状态转移、递归分治),能显著提升程序的时间/空间效率。以Leetcode hot100为代表的精选题库,汇集了FAANG等科技巨头的高频面试题,如两数之和、零钱兑换等经典问题,既可作为算法能力试金石,也是工程实践中解决性能瓶颈的利器。通过系统化的三遍刷题法和配套工具链,开发者能有效掌握算法思维,应对分布式系统、大数据处理等场景的复杂问题。

weixin_34221276的博客 365

Leetcode HOT 100 题目总结(已完结)

文章目录前引题目博客链接Easy No.1 - No.21 前引 这段时间感觉动态规划已经做伤了 就是真的没什么动力再做下去了 后面没做的也都是难的不行的dp题目了 想着还是要做的 这段时间换点口味 把力扣HOT 100题给全做了 写个总结 题目博客链接 Easy No.1 - No.21 461. 汉明距离 617. 合并二叉树 104. 二叉树的最大深度 206. 反转链表 169. 多数元素 21. 合并两个有序链表 ...

Love 6's Private Blog 1万+

Leecode Hot100

【代码】Leecode Hot100。

weixin_45014721的博客 649

力扣hot100 | 动态规划1 | 70. 爬楼梯、118. 杨辉三角、198. 打家劫舍、279. 完全平方数、322. 零钱兑换

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?示例 1:输入:n = 2输出:2解释:有两种方法可以爬到楼顶。1. 1 阶 + 1 阶2. 2 阶示例 2:输入:n = 3输出:3解释:有三种方法可以爬到楼顶。1. 1 阶 + 1 阶 + 1 阶2. 1 阶 + 2 阶3. 2 阶 + 1 阶。

m0_56231308的博客 1127

微信抢红包神器自动抢软件

微信抢红包神器自动抢软件

weixin_44006731的博客 8080

Hopf振荡器在机器人步态控制里到底怎么用?一个CPG仿生案例说清楚

本文深入解析了Hopf振荡器在机器人步态控制中的实际应用,通过CPG仿生案例详细展示了从数学方程到关节指令的完整流程。重点探讨了Hopf振荡器的极限环稳定性、参数调节技巧及自适应控制策略,为机器人运动控制提供了高效解决方案。

weixin_29284657的博客 200

力扣hot100

【代码】力扣hot100。

qq_59768361的博客 1400

矩阵LED和矩阵按键

先说矩阵LED,如图: 下面以行几、列几的表达方法说明 三极管可以当做开关使用 由图可知,如果想让一个LED亮,那么它对应的行和列的三极管都要导通。如果这个矩阵每次只亮一个LED,那么正常写程序没问题。 如果我们想让LED1和LED6亮,其他灯不亮,则需要开启行1、行2、列1、列2,随之带来的问题就是LED2和LED5也会跟着亮起来。 解决方法类似于扫描,因为单片机运行速度很快,可以在很短的时间内开关数次而肉眼看不到。所以我们可以每次只亮一列(排)灯,亮单位时间后关掉同时开启另外一列(排),如此四次一循环

qq_46615634的博客 5789

最详细,最简单的力扣(leetcode)hot 100 动态规划(上)篇讲解

本期带来的是力扣 hot 100里面关于动态规划内容。希望本篇博客能帮助到正在学历力扣 hot 100的你

yyyCode的博客 1109

hfss仿真软件入门教程

hfss仿真软件入门教程 1.模型建立 1.1在project种选择insert hfss design 1.2.在hfss-》solution type 中选择modal 1.3.在moderler-》中选择units 设置单温为mm 1.4进行画图操作,这里为提高效率直接导入一个已经画好的cad图。使用modeler-》import 2.设置端口 2.1在更改模型中的材料 选择需要更改材料...

xunshui2007的博客 3万+

小程序强制更新避坑指南:手把手教你实现无缝升级

本文详细解析小程序强制更新的实现方法,重点介绍wx.getUpdateManager API的使用技巧,帮助开发者规避冷热启动机制下的版本管理陷阱。通过实战案例展示如何设计多级更新提示策略,确保用户无缝升级,提升小程序版本更新率。

star的博客 280

leetcode HOT100总结

本人菜鸡一枚,历时两个月时间把HOT100题做完(Ctrl C-V)了,做完之后还是感觉到很虚,很多中等题还是不会做,于是乎花几天时间把这100题给总结一下。一方面,对自己的知识梳理;另一方面,便于后续回顾。(完成度99,是因为有一道题目收费,没有做!哈哈哈!)以下所有题目都是用Python3实现的。 下面是对这些题目按照算法进行分类整体,主要包括排序、哈希表、递归\回溯、链表、双指针、动态规划、二分查找、贪心、树、深度优先搜索、广度优先搜索等。 在整理之前,先学习一下Python的基本数据类型有哪些,请

qq_36561737的博客 4744

数据仓库ODS层详解- 功能、设计与最佳实践

数据仓库ODS层是大数据分析的基石,为企业决策提供可靠数据源。本文深入探讨ODS层设计原则、实施要点和最佳实践,涵盖金融、零售等行业应用。重点关注云环境下ODS层部署策略,以及实时数据集成、数据湖技术等创新趋势。文章还分析了数据体量增长、实时性需求等挑战,提供实用解决方案。whether助您构建高效、安全、可扩展的ODS层,为数字化转型奠定坚实基础。#数据仓库 #ODS层 #大数据分析 #云计算 #数据湖

一个8年大数据开发工程师的碎碎念 1万+

LeetCode 热题 HOT 100 题解(仅记录解题思路)

由于数组中只有一个元素出现一次,其余元素都出现两次,因此用集合中的元素之和的两倍减去数组中的元素之和,剩下的数就是数组中只出现一次的数字。遍历数组中的每个数字,如果集合中没有该数字,则将该数字加入集合,如果集合中已经有该数字,则将该数字从集合中删除,最后剩下的数字就是只出现一次的数字。指针p1在头结点处,指针p2在头结点的next处,然后p1每次移动1格,p2则走2步,若在其中一个进入null之前两者指向同一结点,则代表有环。使用双指针,左指针指向当前已经处理好的序列的尾部,右指针指向待处理序列的头部。

a131529的博客 1万+

【图像拼接】源码精读:Parallax-Tolerant Unsupervised Deep Image Stitching(UDIS++)

注:Pytorch代码。【图像拼接论文精读】专栏对应文章【图像拼接】论文精读:Parallax-Tolerant Unsupervised Deep Image Stitching(UDIS++)配合对应的文章阅读,效果更佳!注:请重点关注代码段中的注释!!!有一些讲解的东西直接写在代码段的注释中了,同时多关注红色字体和绿色字体!!!我认为深度学习方法和传统方法有很多相似之处。比如:深度学习中的损失函数和传统方法中的对齐项、失真项等其实原理相同,只是求解方式不同。

主要更新底层视觉(去噪、超分等)相关的科研内容,形式为【论文精读】+【论文复现】 7272

leetcode hot100 动态规划

hot100中动态规划相关题目

m0_49860814的博客 1061

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Hot 100总结【leetcode】

leetcode hot100总结

weixin_44911248的博客 6639

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

力扣hot100二刷——动态规划

第二次刷题不在idea写代码,而是直接在leetcode网站上写,“逼”自己掌握常用的函数。

weixin_49426115的博客 973

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

力扣 (LeetCode) LeetCode HOT 100

LeetCode-HOT-100力扣 (LeetCode) ????LeetCode 热题 HOT 100 ⚡ ???? 如果你有问题https://webvueblog.github.io/LeetCode-HOT-100/1. 两数之和2. 两数相加3. 无重复字符的最长子串4. 寻找两个正序数组的中位数5. 最长回文子串10. 正则表达式匹配11. 盛最多水的容器15. 三数之和17. 电话号码的字母...

程序员哆啦A梦,蓝胖子 2512

LeetCode Hot100(动态规划)

我们直接可以手动模拟,设置dpi是当前位置是否能够被拼接成功,那么我们每一次枚举到一个位置,就去枚举所有的字串,如果当前的字串能够完全的匹配i和i-length+1的字串,就去看看i-length是否可以,如果可以当前位置也就可以了。我们由于只能分成两个集合,那么两个集合的和明显是总的和/2 ,记录总和为sum,每个数组的和也就是sum/2,又发现,每个元素只能拿一个,那我们如果能够抽起来sum/2就可以了,去跑一便01背包。不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。

asom12的博客 1326

【力扣hot100】刷题笔记Day24

动态规划1:爬楼梯 + 杨辉三角 + 打家劫舍 + 完全平方数 + 零钱兑换

小涛44的博客 1008

leetcode hot100普通动态规划/基础DP

从s头遍历到尾部, 遍历到i时, 如果0~i存在一个j使得s[0,j]在字典中且s[j,i]在字典中, 那么说明s[0,i]在字典中,即dp[i]=true,那么此处就存在一个DP,每次步入一个新的i,判断其中是否存在j使得上述成立, 直至i=s.length()如果出现负数, 那么前一位的最大值会变成最小值, 前一位的最小值会变成最大值, 那么当前的最大值=Math.max(前面的最大值*当前值,当前值),当前的最小值=Math.min(前面的最小值*当前值, 当前值)

weixin_74191696的博客 1244

HOT 100(导航)【LeetCode】

HOT 100(导航)【LeetCode】

小心星的博客 858

LeetCode Hot100---动态规划

LeetCode Hot100---动态规划

记录学习与开发的过程。 1452

【力扣hot100】动态规划专题|70、118、198、279、322、139、300、152、416、32

动态规划核心是状态定义与转移方程。典型题目:爬楼梯(f[i]=f[i-1]+f[i-2])、打家劫舍(取或不取)、完全平方数、零钱兑换(自底向上)、单词拆分、最长递增子序列(接在更小元素后)。关键在于通过子问题推导整体最优解。

2401_87144364的博客 468
上一篇: LeetCode Hot100(69/100)—— 139. 单词拆分
下一篇: LeetCode Hot100(71/100)——152. 乘积最大子数组
TracyCoder123
博客等级 码龄8年 1万+粉丝 226原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TracyCoder123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值