From 56180d2d9aeae845734a1f9a790c094aec67ac68 Mon Sep 17 00:00:00 2001 From: youngyangyang04 <826123027@qq.com> Date: Sun, 23 May 2021 11:11:29 +0800 Subject: [PATCH] Update --- README.md | 7 ++--- problems/0063.不同路径II.md | 2 -- problems/0343.整数拆分.md | 13 +++++++-- problems/0349.两个数组的交集.md | 18 ++++++++++-- problems/背包理论基础01背包-1.md | 36 ++++++++---------------- problems/背包理论基础01背包-2.md | 4 +-- 6 files changed, 43 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index d2f4520e..82c65c7a 100644 --- a/README.md +++ b/README.md @@ -170,10 +170,9 @@ 6. [链表:删除链表的倒数第 N 个结点](./problems/0019.删除链表的倒数第N个节点.md) 7. [链表:链表相交](./problems/面试题02.07.链表相交.md) 8. [链表:环找到了,那入口呢?](./problems/0142.环形链表II.md) -9. [链表:删除链表的倒数第 N 个结点](./problems/0019.删除链表的倒数第N个节点.md) -10. [哈希表:解决了两数之和,那么能解决三数之和么?](./problems/0015.三数之和.md) -11. [双指针法:一样的道理,能解决四数之和](./problems/0018.四数之和.md) -12. [双指针法:总结篇!](./problems/双指针总结.md) +9. [哈希表:解决了两数之和,那么能解决三数之和么?](./problems/0015.三数之和.md) +10. [双指针法:一样的道理,能解决四数之和](./problems/0018.四数之和.md) +11. [双指针法:总结篇!](./problems/双指针总结.md) ## 栈与队列 diff --git a/problems/0063.不同路径II.md b/problems/0063.不同路径II.md index 311f712e..121629d0 100644 --- a/problems/0063.不同路径II.md +++ b/problems/0063.不同路径II.md @@ -157,8 +157,6 @@ public: * 时间复杂度O(n * m) n m 分别为obstacleGrid 长度和宽度 * 空间复杂度O(n * m) -至于能不能优化空间降为一维dp数组,我感觉不太行,因为要考虑障碍,如果把这些障碍压缩到一行,结果一定就不一样了。 - ## 总结 本题是[62.不同路径](https://mp.weixin.qq.com/s/MGgGIt4QCpFMROE9X9he_A)的障碍版,整体思路大体一致。 diff --git a/problems/0343.整数拆分.md b/problems/0343.整数拆分.md index e7550285..e10a3388 100644 --- a/problems/0343.整数拆分.md +++ b/problems/0343.整数拆分.md @@ -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的初始化 diff --git a/problems/0349.两个数组的交集.md b/problems/0349.两个数组的交集.md index b5116ee1..8a6b0a40 100644 --- a/problems/0349.两个数组的交集.md +++ b/problems/0349.两个数组的交集.md @@ -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 ----------------------- diff --git a/problems/背包理论基础01背包-1.md b/problems/背包理论基础01背包-1.md index e20cec59..6a43ce05 100644 --- a/problems/背包理论基础01背包-1.md +++ b/problems/背包理论基础01背包-1.md @@ -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> dp(weight.size() + 1, vector(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> dp(weight.size() + 1, vector(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) diff --git a/problems/背包理论基础01背包-2.md b/problems/背包理论基础01背包-2.md index f5c747c7..0bd81aad 100644 --- a/problems/背包理论基础01背包-2.md +++ b/problems/背包理论基础01背包-2.md @@ -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 weight = {1, 3, 4}; vector value = {15, 20, 30};