leetcode-master/problems/背包总结篇.md

105 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<p align="center">
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
<a href="https://space.bilibili.com/525438321"><img src="https://img.shields.io/badge/B站-代码随想录-orange" alt=""></a>
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ"><img src="https://img.shields.io/badge/知识星球-代码随想录-blue" alt=""></a>
</p>
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 听说背包问题很难? 这篇总结篇来拯救你了
年前我们已经把背包问题都讲完了,那么现在我们要对背包问题进行总结一番。
背包问题是动态规划里的非常重要的一部分,所以我把背包问题单独总结一下,等动态规划专题更新完之后,我们还会在整体总结一波动态规划。
关于这几种常见的背包,其关系如下:
![416.分割等和子集1](https://img-blog.csdnimg.cn/20210117171307407.png)
通过这个图,可以很清晰分清这几种常见背包之间的关系。
在讲解背包问题的时候,我们都是按照如下五部来逐步分析,相信大家也体会到,把这五部都搞透了,算是对动规来理解深入了。
1. 确定dp数组dp table以及下标的含义
2. 确定递推公式
3. dp数组如何初始化
4. 确定遍历顺序
5. 举例推导dp数组
**其实这五部里哪一步都很关键,但确定递推公式和确定遍历顺序都具有规律性和代表性,所以下面我从这两点来对背包问题做一做总结**
## 背包递推公式
问能否能装满背包或者最多装多少dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]); ,对应题目如下:
* [动态规划416.分割等和子集](https://programmercarl.com/0416.分割等和子集.html)
* [动态规划1049.最后一块石头的重量 II](https://programmercarl.com/1049.最后一块石头的重量II.html)
问装满背包有几种方法dp[j] += dp[j - nums[i]] ,对应题目如下:
* [动态规划494.目标和](https://programmercarl.com/0494.目标和.html)
* [动态规划518. 零钱兑换 II](https://programmercarl.com/0518.零钱兑换II.html)
* [动态规划377.组合总和Ⅳ](https://programmercarl.com/0377.组合总和Ⅳ.html)
* [动态规划70. 爬楼梯进阶版(完全背包)](https://programmercarl.com/0070.爬楼梯完全背包版本.html)
问背包装满最大价值dp[j] = max(dp[j], dp[j - weight[i]] + value[i]); ,对应题目如下:
* [动态规划474.一和零](https://programmercarl.com/0474.一和零.html)
问装满背包所有物品的最小个数dp[j] = min(dp[j - coins[i]] + 1, dp[j]); ,对应题目如下:
* [动态规划322.零钱兑换](https://programmercarl.com/0322.零钱兑换.html)
* [动态规划279.完全平方数](https://programmercarl.com/0279.完全平方数.html)
## 遍历顺序
### 01背包
在[动态规划关于01背包问题你该了解这些](https://programmercarl.com/背包理论基础01背包-1.html)中我们讲解二维dp数组01背包先遍历物品还是先遍历背包都是可以的且第二层for循环是从小到大遍历。
和[动态规划关于01背包问题你该了解这些滚动数组](https://programmercarl.com/背包理论基础01背包-2.html)中我们讲解一维dp数组01背包只能先遍历物品再遍历背包容量且第二层for循环是从大到小遍历。
**一维dp数组的背包在遍历顺序上和二维dp数组实现的01背包其实是有很大差异的大家需要注意**
### 完全背包
说完01背包再看看完全背包。
在[动态规划:关于完全背包,你该了解这些!](https://programmercarl.com/背包问题理论基础完全背包.html)中讲解了纯完全背包的一维dp数组实现先遍历物品还是先遍历背包都是可以的且第二层for循环是从小到大遍历。
但是仅仅是纯完全背包的遍历顺序是这样的题目稍有变化两个for循环的先后顺序就不一样了。
**如果求组合数就是外层for循环遍历物品内层for遍历背包**
**如果求排列数就是外层for遍历背包内层for循环遍历物品**
相关题目如下:
* 求组合数:[动态规划518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html)
* 求排列数:[动态规划377. 组合总和 Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA)、[动态规划70. 爬楼梯进阶版(完全背包)](https://programmercarl.com/0070.爬楼梯完全背包版本.html)
如果求最小数那么两层for循环的先后顺序就无所谓了相关题目如下
* 求最小数:[动态规划322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html)、[动态规划279.完全平方数](https://programmercarl.com/0279.完全平方数.html)
**对于背包问题,其实递推公式算是容易的,难是难在遍历顺序上,如果把遍历顺序搞透,才算是真正理解了**
## 总结
**这篇背包问题总结篇是对背包问题的高度概括,讲最关键的两部:递推公式和遍历顺序,结合力扣上的题目全都抽象出来了**
**而且每一个点,我都给出了对应的力扣题目**
最后如果你想了解多重背包,可以看这篇[动态规划:关于多重背包,你该了解这些!](https://programmercarl.com/背包问题理论基础多重背包.html),力扣上还没有多重背包的题目,也不是面试考察的重点。
如果把我本篇总结出来的内容都掌握的话,可以说对背包问题理解的就很深刻了,用来对付面试中的背包问题绰绰有余!
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>