This commit is contained in:
youngyangyang04
2021-05-23 11:11:29 +08:00
parent 942bd655b6
commit 56180d2d9a
6 changed files with 43 additions and 37 deletions

View File

@ -157,8 +157,6 @@ public:
* 时间复杂度O(n * m) n m 分别为obstacleGrid 长度和宽度
* 空间复杂度O(n * m)
至于能不能优化空间降为一维dp数组我感觉不太行因为要考虑障碍如果把这些障碍压缩到一行结果一定就不一样了。
## 总结
本题是[62.不同路径](https://mp.weixin.qq.com/s/MGgGIt4QCpFMROE9X9he_A)的障碍版,整体思路大体一致。

View File

@ -8,6 +8,8 @@
## 343. 整数拆分
题目链接https://leetcode-cn.com/problems/integer-break/
给定一个正整数 n将其拆分为至少两个正整数的和并使这些整数的乘积最大化。 返回你可以获得的最大乘积。
示例 1:
@ -51,9 +53,16 @@ dp[i]的定义讲贯彻整个解题过程,下面哪一步想不懂了,就想
j是从1开始遍历拆分j的情况在遍历j的过程中其实都计算过了。
那么从1遍历j比较(i - j) * j和dp[i - j] * j 取最大的。
**那有同学问了j怎么就不拆分呢**
j是从1开始遍历拆分j的情况在遍历j的过程中其实都计算过了。那么从1遍历j比较(i - j) * j和dp[i - j] * j 取最大的。递推公式dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));
也可以这么理解j * (i - j) 是单纯的把整数拆分为两个数相乘而j * dp[i - j]是拆分成两个以及两个以上的个数相乘。
如果定义dp[i - j] * dp[j] 也是默认将一个数强制拆成4份以及4份以上了。
所以递推公式dp[i] = max({dp[i], (i - j) * j, dp[i - j] * j});
递推公式dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));
3. dp的初始化

View File

@ -11,7 +11,8 @@
> 如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费!
# 349. 两个数组的交集
## 349. 两个数组的交集
https://leetcode-cn.com/problems/intersection-of-two-arrays/
@ -23,7 +24,7 @@ https://leetcode-cn.com/problems/intersection-of-two-arrays/
输出结果中的每个元素一定是唯一的。
我们可以不考虑输出结果的顺序。
# 思路
## 思路
这道题目主要要学会使用一种哈希数据结构unordered_set这个数据结构可以解决很多类似的问题。
@ -31,7 +32,7 @@ https://leetcode-cn.com/problems/intersection-of-two-arrays/
这道题用暴力的解法时间复杂度是O(n^2),那来看看使用哈希法进一步优化。
那么用数组来做哈希表也是不错的选择,例如[242. 有效的字母异位词](https://mp.weixin.qq.com/s/vM6OszkM6L1Mx2Ralm9Dig)[0383.赎金信](https://mp.weixin.qq.com/s/sYZIR4dFBrw_lr3eJJnteQ)
那么用数组来做哈希表也是不错的选择,例如[242. 有效的字母异位词](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)
但是要注意,**使用数组来做哈希的题目,是因为题目都限制了数值的大小。**
@ -52,6 +53,7 @@ std::set和std::multiset底层实现都是红黑树std::unordered_set的底
![set哈希法](https://img-blog.csdnimg.cn/2020080918570417.png)
C++代码如下:
```C++
class Solution {
public:
@ -69,6 +71,13 @@ public:
};
```
## 拓展
那有同学可能问了遇到哈希问题我直接都用set不就得了用什么数组啊。
直接使用set 不仅占用空间比数组大而且速度要比数组慢set把数值映射到key上都要做hash计算的。
不要小瞧 这个耗时,在数据量大的情况,差距是很明显的。
## 其他语言版本
@ -114,6 +123,9 @@ Python
Go
## 相关题目
* 350.两个数组的交集 II
-----------------------

View File

@ -102,30 +102,13 @@ leetcode上没有纯01背包的问题都是01背包应用方面的题目
dp[0][j]i为0存放编号0的物品的时候各个容量的背包所能存放的最大价值。
代码如下:
```
// 倒叙遍历
for (int j = bagWeight; j >= weight[0]; j--) {
dp[0][j] = dp[0][j - weight[0]] + value[0]; // 初始化i为0时候的情况
}
```
**大家应该发现,这个初始化为什么是倒叙的遍历的?正序遍历就不行么?**
正序遍历还真就不行dp[0][j]表示容量为j的背包存放物品0时候的最大价值物品0的价值就是15因为题目中说了**每个物品只有一个!**所以dp[0][j]如果不是初始值的话就应该都是物品0的价值也就是15。
但如果一旦正序遍历了那么物品0就会被重复加入多次 例如代码如下:
```
// 正序遍历
for (int j = weight[0]; j <= bagWeight; j++) {
dp[0][j] = dp[0][j - weight[0]] + value[0];
dp[0][j] = value[0];
}
```
例如dp[0][1] 是15到了dp[0][2] = dp[0][2 - 1] + 15; 也就是dp[0][2] = 30 了那么就是物品0被重复放入了。
**所以一定要倒叙遍历保证物品0只被放入一次这一点对01背包很重要后面在讲解滚动数组的时候还会用到倒叙遍历来保证物品使用一次**
此时dp数组初始化情况如图所示
@ -138,16 +121,23 @@ dp[i][j]在推导的时候一定是取价值最大的数,如果题目给的价
如果题目给的价值有负数那么非0下标就要初始化为负无穷了。例如一个物品的价值是-2但对应的位置依然初始化为0那么取最大值的时候就会取0而不是-2了所以要初始化为负无穷。
而背包问题的物品价值都是正整数所以初始化为0就可以了。
**这样才能让dp数组在递归公式的过程中取最大的价值而不是被初始值覆盖了**
如图:
![动态规划-背包问题10](https://code-thinking.cdn.bcebos.com/pics/动态规划-背包问题10.jpg)
最后初始化代码如下:
```
// 初始化 dp
vector<vector<int>> dp(weight.size() + 1, vector<int>(bagWeight + 1, 0));
for (int j = bagWeight; j >= weight[0]; j--) {
dp[0][j] = dp[0][j - weight[0]] + value[0];
for (int j = weight[0]; j <= bagWeight; j++) {
dp[0][j] = value[0];
}
```
**费了这么大的功夫才把如何初始化讲清楚相信不少同学平时初始化dp数组是凭感觉来的但有时候感觉是不靠谱的**
@ -239,8 +229,8 @@ void test_2_wei_bag_problem1() {
vector<vector<int>> dp(weight.size() + 1, vector<int>(bagWeight + 1, 0));
// 初始化
for (int j = bagWeight; j >= weight[0]; j--) {
dp[0][j] = dp[0][j - weight[0]] + value[0];
for (int j = weight[0]; j <= bagWeight; j++) {
dp[0][j] = value[0];
}
// weight数组的大小 就是物品个数
@ -285,8 +275,6 @@ Python
Go
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)

View File

@ -104,7 +104,7 @@ for(int i = 0; i < weight.size(); i++) { // 遍历物品
为什么呢?
**倒叙遍历是为了保证物品i只被放入一次**,在[动态规划关于01背包问题你该了解这些](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w)中讲解二维dp数组初始化dp[0][j]时候已经讲解到过一次。
**倒叙遍历是为了保证物品i只被放入一次**。但如果一旦正序遍历了那么物品0就会被重复加入多次
举一个例子物品0的重量weight[0] = 1价值value[0] = 15
@ -152,7 +152,7 @@ dp[1] = dp[1 - weight[0]] + value[0] = 15
## 一维dp01背包完整C++测试代码
```
```C++
void test_1_wei_bag_problem() {
vector<int> weight = {1, 3, 4};
vector<int> value = {15, 20, 30};