没有合适的资源?快使用搜索试试~ 我知道了~
首页程序员Carl的「代码随想录」背包问题深度解析与刷题指南
程序员Carl的「代码随想录」背包问题深度解析与刷题指南
需积分: 14 5 下载量 19 浏览量
更新于2024-07-14
收藏 5.32MB PDF 举报
"「代码随想录」背包问题专题精讲(v1.0)是一本由程序员Carl编写的PDF资料,涵盖了10道LeetCode经典的01背包问题题目的详细讲解。背包问题在动态规划中占有重要地位,而该专题特别关注01背包的完全背包部分,未涉及多重背包,因为力扣平台上的相应题目较少。作者强调背包问题的理解应围绕动态规划的五大步骤进行:确定dp数组、递推公式、初始化、遍历顺序和推导dp数组,这些步骤相互关联且至关重要。 专题内容包括了背包问题的基础理论,如多种类型的背包(如完全背包、多重背包、混合背包、二维费用背包和分组背包)之间的关系,通过清晰的图表帮助读者区分。此外,作者还推荐关注「代码随想录」公众号,获取更多动态规划专题更新及额外的学习资源,如「力扣刷题攻略」项目,其中包含100多道经典算法题目的刷题顺序、详尽的图解、常用算法模板和难点视频讲解,对于想要系统学习和刷题的同学来说非常实用。 该PDF共计4万字,具有严谨缜密的风格,是全网最全面的背包问题教程。按照书中的题目顺序学习将有助于加深对动态规划的理解。无论是初学者还是进阶者,都可以从中找到适合自己的学习路径。最后,作者呼吁读者通过star支持他的GitHub项目,共同进步。" 「代码随想录」背包问题专题精讲提供了一个系统化的学习平台,不仅涵盖了基础知识,还提供了实战刷题策略,对于提升动态规划技能和解决实际问题具有很大的帮助。
资源详情
资源推荐
3. ⼀维dp数组如何初始化
关于初始化,⼀定要和dp数组的定义吻合,否则到递推公式的时候就会越来越乱。
dp[j]表示:容量为j的背包,所背的物品价值可以最⼤为dp[j],那么dp[0]就应该是0,因为背包容量为0
所背的物品的最⼤价值就是0。
那么dp数组除了下标0的位置,初始为0,其他下标应该初始化多少呢?
看⼀下递归公式:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
dp数组在推导的时候⼀定是取价值最⼤的数,如果题⽬给的价值都是正整数那么⾮0下标都初始化为0就
可以了,如果题⽬给的价值有负数,那么⾮0下标就要初始化为负⽆穷。
这样才能让dp数组在递归公式的过程中取的最⼤的价值,⽽不是被初始值覆盖了。
那么我假设物品价值都是⼤于0的,所以dp数组初始化的时候,都初始为0就可以了。
4. ⼀维dp数组遍历顺序
代码如下:
这⾥⼤家发现和⼆维dp的写法中,遍历背包的顺序是不⼀样的!
⼆维dp遍历的时候,背包容量是从⼩到⼤,⽽⼀维dp遍历的时候,背包是从⼤到⼩。
为什么呢?
倒叙遍历是为了保证物品i只被放⼊⼀次!,在动态规划:关于01背包问题,你该了解这些!中讲解⼆维
dp数组初始化dp[0][j]时候已经讲解到过⼀次。
举⼀个例⼦:物品0的重量weight[0] = 1,价值value[0] = 15
如果正序遍历
dp[1] = dp[1 - weight[0]] + value[0] = 15
dp[2] = dp[2 - weight[0]] + value[0] = 30
此时dp[2]就已经是30了,意味着物品0,被放⼊了两次,所以不能正序遍历。
为什么倒叙遍历,就可以保证物品只放⼊⼀次呢?
倒叙就是先算dp[2]
dp[2] = dp[2 - weight[0]] + value[0] = 15 (dp数组已经都初始化为0)
dp[1] = dp[1 - weight[0]] + value[0] = 15
所以从后往前循环,每次取得状态不会和之前取得状态重合,这样每种物品就只取⼀次了。
for(int i = 0; i < weight.size(); i++) { // 遍历物品
for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
!
}
}
那么问题⼜来了,为什么⼆维dp数组历的时候不⽤倒叙呢?
因为对于⼆维dp,dp[i][j]都是通过上⼀层即dp[i - 1][j]计算⽽来,本层的dp[i][j]并不会被覆盖!
(如何这⾥读不懂,⼤家就要动⼿试⼀试了,空想还是不靠谱的,实践出真知!)
再来看看两个嵌套for循环的顺序,代码中是先遍历物品嵌套遍历背包容量,那可不可以先遍历背包容量
嵌套遍历物品呢?
不可以!
因为⼀维dp的写法,背包容量⼀定是要倒序遍历(原因上⾯已经讲了),如果遍历背包容量放在上⼀
层,那么每个dp[j]就只会放⼊⼀个物品,即:背包⾥只放⼊了⼀个物品。
(这⾥如果读不懂,就在回想⼀下dp[j]的定义,或者就把两个for循环顺序颠倒⼀下试试!)
所以⼀维dp数组的背包在遍历顺序上和⼆维其实是有很⼤差异的!,这⼀点⼤家⼀定要注意。
5. 举例推导dp数组
⼀维dp,分别⽤物品0,物品1,物品2 来遍历背包,最终得到结果如下:
⼀维dp01背包完整C++测试代码
void test_1_wei_bag_problem() {
vector<int> weight = {1, 3, 4};
vector<int> value = {15, 20, 30};
int bagWeight = 4;
!
// 初始化
vector<int> dp(bagWeight + 1, 0);
for(int i = 0; i < weight.size(); i++) { // 遍历物品
for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
可以看出,⼀维dp 的01背包,要⽐⼆维简洁的多! 初始化 和 遍历顺序相对简单了。
所以我倾向于使⽤⼀维dp数组的写法,⽐较直观简洁,⽽且空间复杂度还降了⼀个数量级!
在后⾯背包问题的讲解中,我都直接使⽤⼀维dp数组来进⾏推导。
总结
以上的讲解可以开发⼀道⾯试题⽬(毕竟⼒扣上没原题)。
就是本⽂中的题⽬,要求先实现⼀个纯⼆维的01背包,如果写出来了,然后再问为什么两个for循环的嵌
套顺序这么写?反过来写⾏不⾏?再讲⼀讲初始化的逻辑。
然后要求实现⼀个⼀维数组的01背包,最后再问,⼀维数组的01背包,两个for循环的顺序反过来写⾏不
⾏?为什么?
注意以上问题都是在候选⼈把代码写出来的情况下才问的。
就是纯01背包的题⽬,都不⽤考01背包应⽤类的题⽬就可以看出候选⼈对算法的理解程度了。
相信⼤家读完这篇⽂章,应该对以上问题都有了答案!
此时01背包理论基础就讲完了,我⽤了两篇⽂章把01背包的dp数组定义、递推公式、初始化、遍历顺序
从⼆维数组到⼀维数组统统深度剖析了⼀遍,没有放过任何难点。
⼤家可以发现其实信息量还是挺⼤的。
如果把动态规划:关于01背包问题,你该了解这些!和本篇的内容都理解了,后⾯我们在做01背包的题
⽬,就会发现⾮常简单了。
不⽤再凭感觉或者记忆去写背包,⽽是有⾃⼰的思考,了解其本质,代码的⽅⽅⾯⾯都在⾃⼰的掌控之
中。
即使代码没有通过,也会有⾃⼰的逻辑去debug,这样就思维清晰了。
接下来就要开始⽤这两天的理论基础去做⼒扣上的背包⾯试题⽬了,录友们握紧扶⼿,我们要上⾼速
啦!
相信很多⼩伙伴刷题的时候⾯对⼒扣上近两千道题⽬,感觉⽆从下⼿,我花费半年时间整理了
Github项⽬:「⼒扣刷题攻略」https://github.com/youngyangyang04/leetcode-master。
⾥⾯有100多道经典算法题⽬刷题顺序、配有40w字的详细图解,常⽤算法模板总结,以及难点视
频讲解,按照list⼀道⼀道刷就可以了!star⽀持⼀波吧!
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
cout << dp[bagWeight] << endl;
}
!
int main() {
test_1_wei_bag_problem();
}
!
公众号:代码随想录
B站:代码随想录
Github:leetcode-master
知乎:代码随想录
动态规划:分割等和⼦集可以⽤01背包!
416. 分割等和⼦集
题⽬链接:https://leetcode-cn.com/problems/partition-equal-subset-sum/
题⽬难易:中等
给定⼀个只包含正整数的⾮空数组。是否可以将这个数组分割成两个⼦集,使得两个⼦集的元素和相
等。
注意:
每个数组中的元素不会超过 100
数组的⼤⼩不会超过 200
示例 1:
输⼊: [1, 5, 11, 5]
输出: true
解释: 数组可以分割成 [1, 5, 5] 和 [11].
示例 2:
输⼊: [1, 2, 3, 5]
输出: false
解释: 数组不能分割成两个元素和相等的⼦集.
思路
剩余80页未读,继续阅读
或许对了
- 粉丝: 233
- 资源: 16
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 前端面试必问:真实项目经验大揭秘
- 永磁同步电机二阶自抗扰神经网络控制技术与实践
- 基于HAL库的LoRa通讯与SHT30温湿度测量项目
- avaWeb-mast推荐系统开发实战指南
- 慧鱼SolidWorks零件模型库:设计与创新的强大工具
- MATLAB实现稀疏傅里叶变换(SFFT)代码及测试
- ChatGPT联网模式亮相,体验智能压缩技术.zip
- 掌握进程保护的HOOK API技术
- 基于.Net的日用品网站开发:设计、实现与分析
- MyBatis-Spring 1.3.2版本下载指南
- 开源全能媒体播放器:小戴媒体播放器2 5.1-3
- 华为eNSP参考文档:DHCP与VRP操作指南
- SpringMyBatis实现疫苗接种预约系统
- VHDL实现倒车雷达系统源码免费提供
- 掌握软件测评师考试要点:历年真题解析
- 轻松下载微信视频号内容的新工具介绍
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功