背包问题(动归)

目录

问能否能装满背包(或者最多装多少):dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]); 对应题目如下:

416.分割等和子集 (物品正序,背包倒序)

问装满背包有几种方法:dp[j] += dp[j - nums[i]] ,对应题目如下:

518. 零钱兑换 II(opens new window)

问背包装满最大价值:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]); ,对应题目如下:

474.一和零

问装满背包所有物品的最小个数:dp[j] = min(dp[j - coins[i]] + 1, dp[j]); ,对应题目如下:

322.零钱兑换(最少个数) 正序 先物品再背包

279.完全平方数(最小数量) 先背包后物品

遍历顺序

01背包

完全背包


背包问题,大家都知道,有N件物品和一个最多能背重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。

背包问题有多种背包方式,常见的有:01背包、完全背包、多重背包、分组背包和混合背包等等。

要注意题目描述中商品是不是可以重复放入。

一个商品如果可以重复多次放入是完全背包,而只能放入一次是01背包,写法还是不一样的。

问能否能装满背包(或者最多装多少):dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]); 对应题目如下:
416.分割等和子集 (物品正序,背包倒序)

给你一个 只包含正整数 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。


这道题目就是一道01背包应用类的题目,需要我们拆解题目,然后套入01背包的场景。

01背包相对于本题,主要要理解,题目中物品是nums[i],重量是nums[i],价值也是nums[i],背包体积是sum/2。

class Solution {public boolean canPartition(int[] nums) {/*** 1. 确定dp数组及下标含义 :容量为j的背包,所背的物品价值最大可以为dp[j],背包价值等于总和的一半* 2. 递推公式 dp[j]=Math.max(dp[j],dp(j-nums[i])+nums[i])* 3. 初始化 dp[0]=0 非零dp[]:0 只包含正整数的非空数组,所以非0下标的元素初始化为0* 4. 遍历顺序 dp[j] 如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历!* 5. 推导结果*/if (nums == null || nums.length == 0) {return false;}int sum = 0;for (int num : nums) {sum += num;}//总和为奇数不能平分if (sum % 2 != 0) {return false;}int target = sum / 2;int[] dp = new int[target + 1];for (int i = 0; i < nums.length; i++) {//物品for (int j = target; j >= nums[i]; j--) {//背包 倒序遍历dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]);}//剪枝一下,每一次完成for-loop,立即检查是否dp[target] == targetif (dp[target] == target) {return true;}}return dp[target] == target;}
}
  • 动态规划:1049.最后一块石头的重量 II(opens new window)
问装满背包有几种方法:dp[j] += dp[j - nums[i]] ,对应题目如下:
  • 动态规划:494.目标和(opens new window)
518. 零钱兑换 II(opens new window)

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

请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。

假设每一种面额的硬币有无限个。


/*** 先物品后背包的情况下,根据递推公式,dp【j】一定是来自于外层上一次的结果,而外层上一次的结果一定是来源于上一个物品的dp数组,所以不会出现物品2在物品1之前的情况,也就是只会出现【物品1,物品1,物品2】这种情况,而物品2不会出现在物品1之前,(不会重复)恰好对应组合问题;* 而外层遍历背包 内层遍历物品就不一样了,每一层的dp【j】都是在固定j的情况下,把物品从头开始遍历,所以dp【j】来自于上一层的结果,而上一层的结果又遍历了所有物品,所以这种遍历方式会出现【物品1,物品2,物品1】这种情况,恰好对应了排列问题* 组合不强调元素之间的顺序,排列强调元素之间的顺序。* * 1.dp[j]:凑成总金额j的货币组合数为dp[j]* 2.dp[j] 就是所有的dp[j - coins[i]](考虑coins[i]的情况)相加。* dp[j] += dp[j - coins[i]];* 3.初始化  dp[0] = 1 下标非0的dp[j]初始化为0,这样累计加dp[j - coins[i]]的时候才不会影响真正的dp[j]* 4.遍历顺序 先物品后背包* 如果求组合数就是外层for循环遍历物品,内层for遍历背包。* 如果求排列数就是外层for遍历背包,内层for循环遍历物品。*/
class Solution {public int change(int amount, int[] coins) {int[] dp = new int[amount + 1];dp[0]=1;//判断条件决定遍历的背包还是物体  求的是组合数for (int i = 0; i <coins.length; i++) {//物品   for (int j = coins[i]; j <=amount ; j++) {//背包  价值到背包dp[j]+=dp[j-coins[i]];}}return dp[amount];}
}
  • 动态规划:377.组合总和Ⅳ(opens new window)
  • 动态规划:70. 爬楼梯进阶版(完全背包)(opens new window)
问背包装满最大价值:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]); ,对应题目如下:
474.一和零

给你一个二进制字符串数组 strs 和两个整数 m 和 n 。

请你找出并返回 strs 的最大子集的长度,该子集中 最多 有 m 个 0 和 n 个 1

如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集

问装满背包所有物品的最小个数:dp[j] = min(dp[j - coins[i]] + 1, dp[j]); ,对应题目如下:

完全背包统一正序遍历

322.零钱兑换(最少个数) 正序 先物品再背包

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

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

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

class Solution {/*** 1.确定dp数组以及下标的含义* dp[i]: 凑足总额为j所需钱币的最少个数为dp[j]* 2.递推公式 在进行递推公式之前通常有对应的条件判断* dp[j] = Math.min(dp[j - coins[i]] + 1, dp[j]);* 3.初始化* dp[0]=0 dp[j]初始化成比较大的数,防止被覆盖* 4.遍历顺序 完全背包(个数不受限制)* 完全背包是正序遍历 求组合数就是外层for循环遍历物品,内层for遍历背包。求排列数就是外层for遍历背包,内层for循环遍历物品。*/public int coinChange(int[] coins, int amount) {//初始化dp数组为最大值int max = Integer.MAX_VALUE;//钱数需要的最少硬币int[] dp = new int[amount + 1];Arrays.fill(dp, max);//初始化dp[0] = 0;for (int i = 0; i < coins.length; i++) { //遍历物品//正序遍历:完全背包问题  每个硬币可以选择多次for (int j = coins[i]; j <= amount; j++) {//只有dp[j-coins[i]]不是初始最大值时,才有选择的必要//在进行递推公式之前通常有对应的条件判断if (dp[j - coins[i]] != max) {//选择硬币数目最小的情况dp[j] = Math.min(dp[j - coins[i]] + 1, dp[j]);}}}//三目运算符比较好用 没有最小值就返回-1return dp[amount]== max ? -1 : dp[amount];}
}
279.完全平方数(最小数量) 先背包后物品

给你一个整数 n ,返回 和为 n 的完全平方数的最少数量

class Solution {public int numSquares(int n) {/*** 完全平方数就是物品(可以无限件使用),凑个正整数n就是背包,问凑满这个背包最少有多少物品?* 1.确定dp数组以及下标的含义* dp[i]: 和为 j 的完全平方数的最少数量为dp[j]* 2.递推公式 在进行递推公式之前通常有对应的条件判断* dp[j] = Math.min(dp[j - i*i] + 1, dp[j]);* 3.初始化* dp[0]=0 dp[j]初始化成比较大的数,防止被覆盖* 4.遍历顺序 完全背包(个数不受限制)* 完全背包是正序遍历* 求排列数就是外层for遍历背包,内层for循环遍历物品。*/// 定义:和为 i 的平方数的最小数量是 dp[i]int[] dp = new int[n + 1];Arrays.fill(dp, Integer.MAX_VALUE);// base casedp[0] = 0;// 状态转移方程for (int i = 1; i <= n; i++) {for (int j = 1; j * j <= i; j++) {// i - j * j 只要再加一个平方数 j * j 即可凑出 idp[i] = Math.min(dp[i], dp[i - j * j] + 1);}}return dp[n];}        `                    
}
遍历顺序
01背包

在动态规划:关于01背包问题,你该了解这些! (opens new window)中我们讲解二维dp数组01背包先遍历物品还是先遍历背包都是可以的,且第二层for循环是从小到大遍历。

和动态规划:关于01背包问题,你该了解这些!(滚动数组) (opens new window)中,我们讲解一维dp数组01背包只能先遍历物品再遍历背包容量,且第二层for循环是从大到小遍历。

完全背包

在动态规划:关于完全背包,你该了解这些! (opens new window)中,讲解了纯完全背包的一维dp数组实现,先遍历物品还是先遍历背包都是可以的,且第二层for循环是从小到大遍历。

但是仅仅是纯完全背包的遍历顺序是这样的,题目稍有变化,两个for循环的先后顺序就不一样了。

如果求组合数就是外层for循环遍历物品,内层for遍历背包。

如果求排列数就是外层for遍历背包,内层for循环遍历物品。

相关题目如下:

  • 求组合数:动态规划:518.零钱兑换II(opens new window)
  • 求排列数:动态规划:377. 组合总和 Ⅳ (opens new window)、动态规划:70. 爬楼梯进阶版(完全背包)(opens new window)

如果求最小数,那么两层for循环的先后顺序就无所谓了,相关题目如下:

  • 求最小数:动态规划:322. 零钱兑换 (opens new window)、动态规划:279.完全平方数(opens new window)

对于背包问题,其实递推公式算是容易的,难是难在遍历顺序上,如果把遍历顺序搞透,才算是真正理解了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/35927.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

父级设置最大宽度,其宽度自适应子级中的内容

父级宽度自适应 1.父级限制最大宽度 2.子级竖着排放,每列的个数明确 3.父级的宽度跟随子级元素的个数变化宽度 tips: 因为父级要设置"background-color"属性,所以父级DIV必须要给明确的宽高,这就意味着纯CSS自适应宽度无法做到(好吧,是我做不到) HTML <temp…

茴香豆接入微信个人助手部署

将rag产品接入微信工作群&#xff0c;自动回答问题&#xff0c;香吗&#xff1f;&#xff1f; let‘s go 1、打开openxlab平台&#xff0c;找到茴香豆web产品应用中心-OpenXLab 点击进入&#xff0c;设置知识库名字和密码 2、上传知识库文件和编辑正反例等 3、然后进行测试问答…

电脑开机之后屏幕没有任何显示?怎么检查?

前言 最近有很多小伙伴来咨询&#xff0c;自己的电脑开机之后&#xff0c;屏幕真的是一点显示都没有&#xff0c;只有CPU风扇在转。 这个情况小白经常经常经常遇到&#xff0c;所以写一篇关于这个问题的排查教程。按照这个教程来排查&#xff0c;除非真的是硬件损坏&#xff…

算法第八天:leetcode234.回文链表

给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为回文链表。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,2,1] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;head [1,2…

面向对象编程——python

目录 一、面向对象编程 1.1 类和对象 1.2 继承 1.3 封装 1.4 多态 1.5 Python中的面向对象编程 二、类、对象和变量 2.1 类&#xff08;Class&#xff09; 2.2.1 类的属性&#xff08;Class Attributes&#xff09; 2.2.2 类的方法&#xff08;Class Methods…

对类与对象的(二)补充

1.Date这样的构造函数 析构函数 拷贝构造 默认构造函数有三种 &#xff1a;全缺省的构造函数 无参的构造函数 和编译器默认生成的构造函数 class Date {pubilc&#xff1a;void Print&#xff08;&#xff09; { } private&#xff1a;//全缺省的int year1;int month1;int …

二叉树的广度优先搜索(层次遍历)

目录 定义 层序遍历的数据结构 实现过程简述 具体代码 定义 层序遍历就是从左到右一层一层地遍历二叉树。 层序遍历的数据结构 层序遍历需要借用一个辅助数据结构实现&#xff0c;由于队列具有先进先出的特性&#xff0c;符合一层一层遍历的逻辑&#xff0c;而栈先进后出…

PHP框架之Laravel框架

Laravel框架详解 Laravel&#xff0c;作为一款广受欢迎的PHP Web开发框架&#xff0c;以其优雅、简洁的语法和强大的功能特性&#xff0c;赢得了全球众多开发者的青睐。下面&#xff0c;我们将从Laravel的特点、应用案例以及具体的框架使用等方面进行详细解析。 一、Laravel框…

甲子光年专访天润融通CEO吴强:客户经营如何穿越低速周期?

作者&#xff5c;陈杨、编辑&#xff5c;栗子 社会的发展从来都是从交流和联络开始的。 从结绳记事到飞马传信&#xff0c;从电话电报到互联网&#xff0c;人类的联络方式一直都在随着时代的发展不断进步。只是传统社会通信受限于技术导致效率低下&#xff0c;对经济社会产生影…

LLaMA:挑战大模型Scaling Law的性能突破

实际问题 在大模型的研发中,通常会有下面一些需求: 计划训练一个10B的模型,想知道至少需要多大的数据?收集到了1T的数据,想知道能训练一个多大的模型?老板准备1个月后开发布会,给的资源是100张A100,应该用多少数据训多大的模型效果最好?老板对现在10B的模型不满意,想…

退市新规解读—财务类强制退市

一、退市风险警示&#xff1a;第一年触及相关指标 上市公司最近一个会计年度触及下列退市风险指标之一&#xff0c;公司股票或存托凭证被实施退市风险警示(*ST)&#xff1a; 第1项 组合类财务指标 仅发行A股或B股&#xff0c;最近一个会计年度或追溯重述后最近一个会计年度 …

Leetcode 102.目标和

给定一个正整数数组 nums 和一个整数 target 。 向数组中的每个整数前添加 ‘’ 或 ‘-’ &#xff0c;然后串联起所有整数&#xff0c;可以构造一个 表达式 &#xff1a; 例如&#xff0c;nums [2, 1] &#xff0c;可以在 2 之前添加 ‘’ &#xff0c;在 1 之前添加 ‘-’ &…

C#面:C#属性能在接口中声明吗?

在C#中&#xff0c;接口是一种定义了一组方法、属性和事件的类型。在接口中&#xff0c;只能声明方法、属性和事件的签名&#xff0c;而不能包含字段、构造函数或实现代码。因此&#xff0c;C#属性不能直接在接口中声明。 然而&#xff0c;你可以在接口中定义属性的签名&#…

VMware的具体使用

&#x1f4d1;打牌 &#xff1a; da pai ge的个人主页 &#x1f324;️个人专栏 &#xff1a; da pai ge的博客专栏 ☁️宝剑锋从磨砺出&#xff0c;梅花香自苦寒来 目录 一&#x1f324;️VMware的安…

用户登录错误次数太多锁定账号

当用户登录验证码错误次数太多时&#xff0c;需要限制用户在10分钟之内不能再次登录。 限制方案&#xff1a; 1.通过Redis ZSet key可以设置为用户名&#xff0c;value可以设置为UUID&#xff0c;score设置为当前时间戳 每次用户登录时&#xff0c;通过 rangeByScore 查询对…

Ubuntu22安装PyCharm

下载&#xff08;社区版&#xff09; 官网下载地址 解压 sudo tar -xzvf pycharm-community-2024.1.4.tar.gz 软件移动到指定目录下&#xff08;根据不同版本修改&#xff09; sudo mv pycharm-community-2024.1.4/ /usr/local/PyCharm/运行 cd /usr/local/PyCharm/pycha…

使用PEFT库进行ChatGLM3-6B模型的LORA高效微调

PEFT库进行ChatGLM3-6B模型LORA高效微调 LORA微调ChatGLM3-6B模型安装相关库使用ChatGLM3-6B模型GPU显存占用准备数据集加载模型加载数据集数据处理数据集处理配置LoRA配置训练超参数开始训练保存LoRA模型模型推理从新加载合并模型使用微调后的模型 LORA微调ChatGLM3-6B模型 本…

6 序列数据和文本的深度学习

6.1 使用文本数据 文本是常用的序列化数据类型之一。文本数据可以看作是一个字符序列或词的序列。对大多数问题&#xff0c;我们都将文本看作词序列。深度学习序列模型(如RNN及其变体)能够从文本数据中学习重要的模式。这些模式可以解决类似以下领域中的问题&#xff1a; 自然…

JVM专题十一:JVM 中的收集器一

上一篇JVM专题十&#xff1a;JVM中的垃圾回收机制专题中&#xff0c;我们主要介绍了Java的垃圾机制&#xff0c;包括垃圾回收基本概念&#xff0c;重点介绍了垃圾回收机制中自动内存管理与垃圾收集算法。如果说收集算法是内存回收的方法论&#xff0c;那么垃圾收集器就是内存回…

【开发者推荐】告别繁琐:一键解锁国产ETL新贵,Kettle的终结者

在数字化转型的今天&#xff0c;数据集成的重要性不言而喻。ETL工具作为数据管理的核心&#xff0c;对企业决策和运营至关重要。尽管Kettle广受欢迎&#xff0c;但国产ETL工具 TASKCTL 以其创新特性和卓越性能&#xff0c;为市场提供了新的选择。 TASKCTL概述 TASKCTL 是一款免…