diff --git a/README.md b/README.md index 3dbf2c0d..02d004e9 100644 --- a/README.md +++ b/README.md @@ -3,35 +3,22 @@ 👉 推荐 [Gitee同步](https://gitee.com/programmercarl/leetcode-master) > 1. **介绍**:本项目是一套完整的刷题计划,旨在帮助大家少走弯路,循序渐进学算法,[关注作者](#关于作者) -> 2. **PDF版本** : [「代码随想录」算法精讲 PDF 版本](https://programmercarl.com/other/algo_pdf.html) 。 -> 3. **算法公开课** : [《代码随想录》算法视频公开课](https://www.bilibili.com/video/BV1fA4y1o715) 。 -> 4. **最强八股文:**:[代码随想录知识星球精华PDF](https://www.programmercarl.com/other/kstar_baguwen.html) -> 5. **刷题顺序** : README已经将刷题顺序排好了,按照顺序一道一道刷就可以。 -> 6. **学习社区** : 一起学习打卡/面试技巧/如何选择offer/大厂内推/职场规则/简历修改/技术分享/程序人生。欢迎加入[「代码随想录」知识星球](https://programmercarl.com/other/kstar.html) 。 -> 7. **提交代码**:本项目统一使用C++语言进行讲解,但已经有Java、Python、Go、JavaScript等等多语言版本,感谢[这里的每一位贡献者](https://github.com/youngyangyang04/leetcode-master/graphs/contributors),如果你也想贡献代码点亮你的头像,[点击这里](https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A)了解提交代码的方式。 -> 8. **转载须知** :以下所有文章皆为我([程序员Carl](https://github.com/youngyangyang04))的原创。引用本项目文章请注明出处,发现恶意抄袭或搬运,会动用法律武器维护自己的权益。让我们一起维护一个良好的技术创作环境! +> 2. **正式出版** :[《代码随想录》](https://programmercarl.com/other/publish.html) 。 +> 3. **PDF版本** : [「代码随想录」算法精讲 PDF 版本](https://programmercarl.com/other/algo_pdf.html) 。 +> 4. **算法公开课** : [《代码随想录》算法视频公开课](https://www.bilibili.com/video/BV1fA4y1o715) 。 +> 5. **最强八股文:**:[代码随想录知识星球精华PDF](https://www.programmercarl.com/other/kstar_baguwen.html) +> 6. **刷题顺序** : README已经将刷题顺序排好了,按照顺序一道一道刷就可以。 +> 7. **学习社区** : 一起学习打卡/面试技巧/如何选择offer/大厂内推/职场规则/简历修改/技术分享/程序人生。欢迎加入[「代码随想录」知识星球](https://programmercarl.com/other/kstar.html) 。 +> 8. **提交代码**:本项目统一使用C++语言进行讲解,但已经有Java、Python、Go、JavaScript等等多语言版本,感谢[这里的每一位贡献者](https://github.com/youngyangyang04/leetcode-master/graphs/contributors),如果你也想贡献代码点亮你的头像,[点击这里](https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A)了解提交代码的方式。 +> 9. **转载须知** :以下所有文章皆为我([程序员Carl](https://github.com/youngyangyang04))的原创。引用本项目文章请注明出处,发现恶意抄袭或搬运,会动用法律武器维护自己的权益。让我们一起维护一个良好的技术创作环境! +

- - - - -

- - - - -

- -

《代码随想录》正式出版啦!!录友专属福利,点击下方可以享五折优惠!详细可以点击这里

- -

- - + +

- # LeetCode 刷题攻略 ## 刷题攻略的背景 diff --git a/problems/0077.组合.md b/problems/0077.组合.md index 9c473bdd..4ce58d33 100644 --- a/problems/0077.组合.md +++ b/problems/0077.组合.md @@ -25,9 +25,13 @@ [1,4], ] -也可以直接看我的B站视频:[带你学透回溯算法-组合问题(对应力扣题目:77.组合)](https://www.bilibili.com/video/BV1ti4y1L7cv#reply3733925949) +# 算法公开课 -## 思路 + +**《代码随想录》算法视频公开课:[带你学透回溯算法-组合问题(对应力扣题目:77.组合)](https://www.bilibili.com/video/BV1ti4y1L7cv),[组合问题的剪枝操作](https://www.bilibili.com/video/BV1wi4y157er),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 + + +# 思路 本题这是回溯法的经典题目。 @@ -122,7 +126,7 @@ vector path; // 用来存放符合条件结果 为什么要有这个startIndex呢? -**每次从集合中选取元素,可选择的范围随着选择的进行而收缩,调整可选择的范围,就是要靠startIndex**。 +**建议在[77.组合视频讲解](https://www.bilibili.com/video/BV1ti4y1L7cv)中,07:36的时候开始听,startIndex 就是防止出现重复的组合**。 从下图中红线部分可以看出,在集合[1,2,3,4]取1之后,下一层递归,就要在[2,3,4]中取数了,那么下一层递归如何知道从[2,3,4]中取数呢,靠的就是startIndex。 diff --git a/problems/0077.组合优化.md b/problems/0077.组合优化.md index b8b5f3c1..c8a5837d 100644 --- a/problems/0077.组合优化.md +++ b/problems/0077.组合优化.md @@ -6,12 +6,12 @@ +# 77.组合优化 +**《代码随想录》算法视频公开课:[组合问题的剪枝操作](https://www.bilibili.com/video/BV1wi4y157er),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 在[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)中,我们通过回溯搜索法,解决了n个数中求k个数的组合问题。 -> 可以直接看我的B栈视频讲解:[带你学透回溯算法-组合问题的剪枝操作](https://www.bilibili.com/video/BV1wi4y157er) - 文中的回溯法是可以剪枝优化的,本篇我们继续来看一下题目77. 组合。 链接:https://leetcode.cn/problems/combinations/ @@ -84,9 +84,11 @@ for (int i = startIndex; i <= n; i++) { 1. 已经选择的元素个数:path.size(); -2. 还需要的元素个数为: k - path.size(); +2. 所需需要的元素个数为: k - path.size(); -3. 在集合n中至多要从该起始位置 : n - (k - path.size()) + 1,开始遍历 +3. 列表中剩余元素(n-i) >= 所需需要的元素个数(k - path.size()) + +4. 在集合n中至多要从该起始位置 : i <= n - (k - path.size()) + 1,开始遍历 为什么有个+1呢,因为包括起始位置,我们要是一个左闭的集合。 diff --git a/problems/0098.验证二叉搜索树.md b/problems/0098.验证二叉搜索树.md index 727144d5..5deaed52 100644 --- a/problems/0098.验证二叉搜索树.md +++ b/problems/0098.验证二叉搜索树.md @@ -20,6 +20,11 @@ ![98.验证二叉搜索树](https://img-blog.csdnimg.cn/20210203144334501.png) +# 视频讲解 + +**《代码随想录》算法视频公开课:[你对二叉搜索树了解的还不够! | LeetCode:98.验证二叉搜索树](https://www.bilibili.com/video/BV18P411n7Q4),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 + + # 思路 要知道中序遍历下,输出的二叉搜索树节点的数值是有序序列。 diff --git a/problems/0108.将有序数组转换为二叉搜索树.md b/problems/0108.将有序数组转换为二叉搜索树.md index b5f322f0..f9f8a4ff 100644 --- a/problems/0108.将有序数组转换为二叉搜索树.md +++ b/problems/0108.将有序数组转换为二叉搜索树.md @@ -31,9 +31,17 @@ 进入正题: -题目中说要转换为一棵高度平衡二叉搜索树。这和转换为一棵普通二叉搜索树有什么差别呢? +题目中说要转换为一棵高度平衡二叉搜索树。为什么强调要平衡呢? -其实这里不用强调平衡二叉搜索树,数组构造二叉树,构成平衡树是自然而然的事情,因为大家默认都是从数组中间位置取值作为节点元素,一般不会随机取,**所以想构成不平衡的二叉树是自找麻烦**。 +因为只要给我们一个有序数组,如果强调平衡,都可以以线性结构来构造二叉搜索树。 + +例如 有序数组[-10,-3,0,5,9] 可以就可以构造成这样的二叉搜索树,如图。 + +![](https://code-thinking-1253855093.file.myqcloud.com/pics/20220930173553.png) + +上图中,是符合二叉搜索树的特性吧,如果要这么做的话,是不是本题意义就不大了,所以才强调是平衡二叉搜索树。 + +其实数组构造二叉树,构成平衡树是自然而然的事情,因为大家默认都是从数组中间位置取值作为节点元素,一般不会随机取。**所以想构成不平衡的二叉树是自找麻烦**。 在[二叉树:构造二叉树登场!](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html)和[二叉树:构造一棵最大的二叉树](https://programmercarl.com/0654.最大二叉树.html)中其实已经讲过了,如果根据数组构造一棵二叉树。 diff --git a/problems/0150.逆波兰表达式求值.md b/problems/0150.逆波兰表达式求值.md index 13b2ba46..306af14b 100644 --- a/problems/0150.逆波兰表达式求值.md +++ b/problems/0150.逆波兰表达式求值.md @@ -89,19 +89,19 @@ C++代码如下: class Solution { public: int evalRPN(vector& tokens) { - stack st; + stack st; for (int i = 0; i < tokens.size(); i++) { if (tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/") { - int num1 = st.top(); + long long num1 = st.top(); st.pop(); - int num2 = st.top(); + long long num2 = st.top(); st.pop(); if (tokens[i] == "+") st.push(num2 + num1); if (tokens[i] == "-") st.push(num2 - num1); - if (tokens[i] == "*") st.push((long)num2 * (long)num1); //力扣改了后台测试数据 + if (tokens[i] == "*") st.push(num2 * num1); if (tokens[i] == "/") st.push(num2 / num1); } else { - st.push(stoi(tokens[i])); + st.push(stoll(tokens[i])); } } int result = st.top(); diff --git a/problems/0216.组合总和III.md b/problems/0216.组合总和III.md index 964facee..ecd3a2c9 100644 --- a/problems/0216.组合总和III.md +++ b/problems/0216.组合总和III.md @@ -7,7 +7,7 @@ -> 别看本篇选的是组合总和III,而不是组合总和,本题和上一篇[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)相比难度刚刚好! +> 别看本篇选的是组合总和III,而不是组合总和,本题和上一篇77.组合相比难度刚刚好! # 216.组合总和III @@ -166,7 +166,7 @@ public: 已选元素总和如果已经大于n(图中数值为4)了,那么往后遍历就没有意义了,直接剪掉。 -那么剪枝的地方一定是在递归终止的地方剪,剪枝代码如下: +那么剪枝的地方可以放在递归函数开始的地方,剪枝代码如下: ```cpp if (sum > targetSum) { // 剪枝操作 @@ -174,6 +174,25 @@ if (sum > targetSum) { // 剪枝操作 } ``` +当然这个剪枝也可以放在 调用递归之前,即放在这里,只不过要记得 要回溯操作给做了。 + +```CPP + +for (int i = startIndex; i <= 9 - (k - path.size()) + 1; i++) { // 剪枝 + sum += i; // 处理 + path.push_back(i); // 处理 + if (sum > targetSum) { // 剪枝操作 + sum -= i; // 剪枝之前先把回溯做了 + path.pop_back(); // 剪枝之前先把回溯做了 + return; + } + backtracking(targetSum, k, sum, i + 1); // 注意i+1调整startIndex + sum -= i; // 回溯 + path.pop_back(); // 回溯 +} +``` + + 和[回溯算法:组合问题再剪剪枝](https://programmercarl.com/0077.组合优化.html) 一样,for循环的范围也可以剪枝,i <= 9 - (k - path.size()) + 1就可以了。 最后C++代码如下: @@ -224,7 +243,7 @@ public: # 其他语言版本 -## Java +## Java 模板方法 ```java @@ -247,7 +266,7 @@ class Solution { if (sum == targetSum) result.add(new ArrayList<>(path)); return; } - + // 减枝 9 - (k - path.size()) + 1 for (int i = startIndex; i <= 9 - (k - path.size()) + 1; i++) { path.add(i); @@ -272,7 +291,7 @@ class Solution { } private void build(int k, int n, int startIndex, int sum) { - + if (sum > n) return; if (path.size() > k) return; @@ -281,7 +300,7 @@ class Solution { ans.add(new ArrayList<>(path)); return; } - + for(int i = startIndex; i <= 9; i++) { path.add(i); sum += i; @@ -328,7 +347,7 @@ class Solution { } ``` -## Python +## Python ```py class Solution: @@ -492,7 +511,7 @@ void backtracking(int targetSum, int k, int sum, int startIndex) { if(sum == targetSum) { int* tempPath = (int*)malloc(sizeof(int) * k); int j; - for(j = 0; j < k; j++) + for(j = 0; j < k; j++) tempPath[j] = path[j]; ans[ansTop++] = tempPath; } @@ -580,7 +599,7 @@ object Solution { // 剪枝 for (i <- startIndex to (9 - (k - path.size) + 1)) { path.append(i) - backtracking(k, n, sum + i, i + 1) + backtracking(k, n, sum + i, i + 1) path = path.take(path.size - 1) } } @@ -592,5 +611,7 @@ object Solution { ``` + + -----------------------
diff --git a/problems/0236.二叉树的最近公共祖先.md b/problems/0236.二叉树的最近公共祖先.md index 82ca09f0..e982493f 100644 --- a/problems/0236.二叉树的最近公共祖先.md +++ b/problems/0236.二叉树的最近公共祖先.md @@ -33,6 +33,11 @@ * 所有节点的值都是唯一的。 * p、q 为不同节点且均存在于给定的二叉树中。 +# 算法公开课 + +**《代码随想录》算法视频公开课:[自底向上查找,有点难度! | LeetCode:236. 二叉树的最近公共祖先](https://www.bilibili.com/video/BV1jd4y1B7E2),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 + + # 思路 遇到这个题目首先想的是要是能自底向上查找就好了,这样就可以找到公共祖先了。 diff --git a/problems/0501.二叉搜索树中的众数.md b/problems/0501.二叉搜索树中的众数.md index a2fdddf4..66919419 100644 --- a/problems/0501.二叉搜索树中的众数.md +++ b/problems/0501.二叉搜索树中的众数.md @@ -33,6 +33,11 @@ 进阶:你可以不使用额外的空间吗?(假设由递归产生的隐式调用栈的开销不被计算在内) +# 算法公开课 + +**《代码随想录》算法视频公开课:[不仅双指针,还有代码技巧可以惊艳到你! | LeetCode:501.二叉搜索树中的众数](https://www.bilibili.com/video/BV1fD4y117gp),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 + + # 思路 这道题目呢,递归法我从两个维度来讲。 diff --git a/problems/0530.二叉搜索树的最小绝对差.md b/problems/0530.二叉搜索树的最小绝对差.md index af1cbd74..811ae89c 100644 --- a/problems/0530.二叉搜索树的最小绝对差.md +++ b/problems/0530.二叉搜索树的最小绝对差.md @@ -19,6 +19,11 @@ 提示:树中至少有 2 个节点。 +# 视频讲解 + +**《代码随想录》算法视频公开课:[二叉搜索树中,需要掌握如何双指针遍历!| LeetCode:530.二叉搜索树的最小绝对差](https://www.bilibili.com/video/BV1DD4y11779),相信结合视频在看本篇题解,更有助于大家对本题的理解**。 + + # 思路 题目中要求在二叉搜索树上任意两节点的差的绝对值的最小值。 diff --git a/problems/0538.把二叉搜索树转换为累加树.md b/problems/0538.把二叉搜索树转换为累加树.md index 5c1e9e8c..63c931d6 100644 --- a/problems/0538.把二叉搜索树转换为累加树.md +++ b/problems/0538.把二叉搜索树转换为累加树.md @@ -78,7 +78,7 @@ pre指针的使用技巧,我们在[二叉树:搜索树的最小绝对差](ht 代码如下: ``` -int pre; // 记录前一个节点的数值 +int pre = 0; // 记录前一个节点的数值 void traversal(TreeNode* cur) ``` @@ -108,7 +108,7 @@ traversal(cur->left); // 左 ```CPP class Solution { private: - int pre; // 记录前一个节点的数值 + int pre = 0; // 记录前一个节点的数值 void traversal(TreeNode* cur) { // 右中左遍历 if (cur == NULL) return; traversal(cur->right); diff --git a/problems/0704.二分查找.md b/problems/0704.二分查找.md index d1389549..b1eaf75a 100644 --- a/problems/0704.二分查找.md +++ b/problems/0704.二分查找.md @@ -223,18 +223,18 @@ class Solution: ```python class Solution: def search(self, nums: List[int], target: int) -> int: - if nums is None or len(nums)==0: - return -1 - left,right=0,len(nums) - while (left target: - right=middle + right = middle else: - left=middle+1 - return -1 + return middle + return -1 ``` **Go:**