news 2026/4/18 4:25:14

代码随想录算法训练营第三十二天:零钱兑换II,组合综合IV,爬楼梯(进阶版)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
代码随想录算法训练营第三十二天:零钱兑换II,组合综合IV,爬楼梯(进阶版)

518.零钱兑换II

文章讲解/视频讲解

题目描述:
给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。

示例 1:

  • 输入: amount = 5, coins = [1, 2, 5]
  • 输出: 4

解释: 有四种方式可以凑成总金额:

  • 5=5
  • 5=2+2+1
  • 5=2+1+1+1
  • 5=1+1+1+1+1

示例 2:

  • 输入: amount = 3, coins = [2]
  • 输出: 0
  • 解释: 只用面额2的硬币不能凑成总金额3。

示例 3:

  • 输入: amount = 10, coins = [10]
  • 输出: 1

注意,你可以假设:

  • 0 <= amount (总金额) <= 5000
  • 1 <= coin (硬币面额) <= 5000
  • 硬币种类不超过 500 种
  • 结果符合 32 位符号整数

思路:
本题就很像之前做过的“目标和”,都是给出背包容量,求装满背包的方法数。但是“目标和”每个元素只能使用一次,前面我们介绍过了这是01背包的特征。而本题每种面额的硬币都有无穷个,所以这就是之前提到过的完全背包,一样来写动态规划五部曲

1.确定dp数组及其下标含义:dp[i][j]:使用 下标为[0, i]的coins[i]能够凑满j(包括j)这么大容量的包,有dp[i][j]种组合方法。

2.确定递推公式:完全背包递推公式与01背包的区别在于:

01背包递推公式为:dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]),01背包如果放了物品i,再取就只能拿物品0到物品i - 1这个范围了,物品i拿不了。

而完全背包公式为:dp[i][j] = max(dp[i - 1][j], dp[i][j - weight[i]] + value[i]),因为有无限个物品,我拿完物品i下一次还是能从物品0到物品i的区间里拿。

本题的一维dp数组递推公式为dp[j] += dp[j - coins[i]],与目标和一致,之前讲过这里不再过多赘述

3.dp数组的初始化:我们要关注的就是dp[0],装满背包容量为0的方法是1,即不放任何物品,dp[0] = 1

4.确定遍历顺序:完全背包的两个for循环随便先后顺序都可以,但是本题不行!因为本题本质和元素凑成的顺序没多大关系,本题描述也是求组合数。假设存在结果221和212,如果求的组合数,那就只有一种,如果是求排列数那么这可就算两种排列了。

我们先来看 外层for循环遍历物品(钱币),内层for遍历背包(金钱总额)的情况。

代码如下:

for (int i = 0; i < coins.size(); i++) { // 遍历物品 for (int j = coins[i]; j <= amount; j++) { // 遍历背包容量 dp[j] += dp[j - coins[i]]; } }

假设:coins[0] = 1,coins[1] = 5。

那么就是先把1加入计算,然后再把5加入计算,得到的方法数量只有{1, 5}这种情况。而不会出现{5, 1}的情况。

所以这种遍历顺序中dp[j]里计算的是组合数!

如果把两个for交换顺序,代码如下:

for (int j = 0; j <= amount; j++) { // 遍历背包容量 for (int i = 0; i < coins.size(); i++) { // 遍历物品 if (j - coins[i] >= 0) dp[j] += dp[j - coins[i]]; } }

背包容量的每一个值,都是经过 1 和 5 的计算,包含了{1, 5} 和 {5, 1}两种情况。

此时dp[j]里算出来的就是排列数!

所以一定是先遍历物品,再遍历背包容量,想不明白就打印数组自己看看

5.举例推导dp数组

输入: amount = 5, coins = [1, 2, 5] ,dp状态图如下:

最后红色框dp[amount]为最终结果。

代码示例:

function change(amount: number, coins: number[]): number { const dp:number[] = new Array(amount + 1).fill(0) dp[0] = 1 for(let i = 0 ; i < coins.length; i++){ for(let j = coins[i]; j <= amount; j++){ dp[j] += dp[j - coins[i]] } } return dp[amount] };

377.组合总和IV

文章讲解/视频讲解

题目描述:

难度:中等

给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数。

示例:

  • nums = [1, 2, 3]
  • target = 4

所有可能的组合为: (1, 1, 1, 1) (1, 1, 2) (1, 2, 1) (1, 3) (2, 1, 1) (2, 2) (3, 1)

请注意,顺序不同的序列被视作不同的组合。

因此输出为 7。

思路:

与上题一样的思路,但是换成了求排列,虽然本题题干说的是求组合,但是我们对组合的定义其实是不强调顺序,即1,5和5,1算同一个组合,但其实算两个不同的排列。

1.确定dp数组及其下标含义:dp[i]:凑成目标正整数为i的排列个数为dp[i]

2.确定递推公式:之前说过了,只要是求装满背包有几种方法,一般都是用:dp[i] += dp[i - nums[j]

3.dp数组如何初始化:dp[0]一定要初始化为1,否则递归其他dp[i]就没有数值基础了,其他全部初始化为0,避免影响dp[i]累加

4.确定遍历顺序:上一题求的是组合,我们先遍历物品再遍历背包,本题求的是排列,所以是先遍历背包再遍历物品。

5.举例来推导dp数组

我们再来用示例中的例子推导一下:

代码示例:

function combinationSum4(nums: number[], target: number): number { const dp:number[] = new Array(target + 1).fill(0) dp[0] = 1 for(let i = 1; i <= target; i++){ for(let j = 0; j < nums.length; j++){ if(i >= nums[j]){ dp[i] += dp[i - nums[j]] } } } return dp[target] };

爬楼梯(进阶)

文章讲解

题目描述:

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬至多m (1 <= m < n)个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

输入描述:输入共一行,包含两个正整数,分别表示n, m

输出描述:输出一个整数,表示爬到楼顶的方法数。

输入示例:3 2

输出示例:3

提示:

当 m = 2,n = 3 时,n = 3 这表示一共有三个台阶,m = 2 代表你每次可以爬一个台阶或者两个台阶。

此时你有三种方法可以爬到楼顶。

  • 1 阶 + 1 阶 + 1 阶段
  • 1 阶 + 2 阶
  • 2 阶 + 1 阶

思路:

其实我们之前就写过一道爬楼梯了,力扣上那道是一次只能爬一节或两节,本题可以爬1到m任意节,其实还是一个完全背包。每次能爬的阶数就是物品,楼顶就是背包容量,我这次跳了一节,下次还能再跳一次一节,也就是物品可以重复使用。而问跳到楼顶有几种方法,其实不就是问装满背包有几种方法吗?

1.确定dp数组及其下标含义:dp[i]:爬到i个台阶的楼顶,有dp[i]种方法

2.确定递推公式:求装满背包有几种方法,递推公式一般都是dp[i] += dp[i - nums[j]];本题比较特殊,dp[i]的来源是dp[i -1],dp[i -2]......,也就是dp[i - j],所以递推公式为dp[i] += dp[i - j]

3.dp数组如何初始化:依旧是dp[0]为1,其他非零下标全是1

4.确定遍历顺序:这里先上一节再上三节,和先上三节再上一节,最后都上了四节,但是算两种不同的方法,前面提到过,这种我们称作排列,也就是背包容量在外面循环,物品在内循环。

5.举例推导dp数组:与上题基本一致

代码示例:

var climbStairs = function (n: number): number { let dp: number[] = new Array(n + 1).fill(0); dp[0] = 1; for (let j = 1; j <= n; j++) {//遍历背包 for (let i = 1; i <= 2; i++) {//遍历物品 if (j - i >= 0) dp[j] = dp[j] + dp[j - i]; } } return dp[n]; }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 14:10:47

DCDC右半零点的物理意义

右半零点的物理意义 在boost与buck-boost变换器中我们都遇见了右半零点&#xff0c;这里我们将进行研究和分析右半零点的物理意义 一、电路中右半零点的形成 在常见的电路例如boost电路中&#xff0c;当在初始时刻&#xff08;即t0&#xff09;负载电流突增&#xff0c;电容 C …

作者头像 李华
网站建设 2026/4/7 4:04:27

张一鸣智慧宝典:解锁成功创业者的微博记录精华

张一鸣智慧宝典&#xff1a;解锁成功创业者的微博记录精华 【免费下载链接】张一鸣微博记录.pdf 本仓库提供了一份珍贵的资料——《张一鸣微博记录.pdf》&#xff0c;这份文档详细整理了字节跳动创始人张一鸣先生在微博上的公开言论与思考分享。张一鸣&#xff0c;作为全球知名…

作者头像 李华
网站建设 2026/4/16 0:24:31

【大数据可视化分析毕设指导】基于Hadoop+Spark的干豆数据分析系统源码,Python+Django实现全流程 毕业设计 选题推荐 毕设选题 数据分析 机器学习

✍✍计算机毕设指导师** ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡有什么问题可以…

作者头像 李华
网站建设 2026/4/12 10:17:26

AI行业应用全景:从金融风控到智能制造的落地实践与技术解析

人工智能已从实验室走向产业纵深&#xff0c;在金融、医疗、教育、制造等关键领域形成规模化应用。本文通过28个真实落地案例、12段核心代码实现、8个可视化流程图和15组关键Prompt设计&#xff0c;系统拆解AI技术从概念验证到商业价值转化的完整路径。每个领域均覆盖技术原理、…

作者头像 李华
网站建设 2026/4/7 22:24:15

GPT-5.2 的“数字公民”身份:参与全球治理、智能决策与未来社会契约

各位社会学家和未来政策制定者们&#xff0c;咱们聊一个有点“烧脑”但又极其现实的话题&#xff1a;GPT-5.2 已经不是一个简单的软件了&#xff0c;它是一个可以自主规划、执行复杂任务、影响数十亿人生活的超级智能体。那么问题来了&#xff1a;这样一个智能体&#xff0c;在…

作者头像 李华
网站建设 2026/4/16 2:53:21

国内AI检测技术超越美国 GPTzero!(SPeedAI)

飞驰星辰发布SpeedAI&#xff1a;以超99%精度引领全球AI检测&#xff0c;获美国竞品官网承认国内AI安全领域迎来里程碑式突破。由北京航空航天大学顶尖计算机博士、硕士团队创立的飞驰星辰公司&#xff0c;今日正式公布其研发的AI生成内容检测产品——SpeedAI。该产品凭借其卓越…

作者头像 李华