mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-06 23:28:29 +08:00
Update
This commit is contained in:
35
README.md
35
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))的原创。引用本项目文章请注明出处,发现恶意抄袭或搬运,会动用法律武器维护自己的权益。让我们一起维护一个良好的技术创作环境!
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="programmercarl.com" target="_blank">
|
||||
<img src="https://code-thinking-1253855093.file.myqcloud.com/pics/20211111115823.png" width="400"/>
|
||||
</a>
|
||||
|
||||
<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://programmercarl.com/other/publish.html">点击这里</a></strong></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://union-click.jd.com/jdc?e=&p=JF8BAMQJK1olXg8EUVhVCkkWAV8IGV8WVAICU24ZVxNJXF9RXh5UHw0cSgYYXBcIWDoXSQVJQwYAUF1UDEsQHDZNRwYlX0B9A1cfakpyYBkSRj4QKFBUEEAfaEcbM244GFIXWQYAUV5VOHsXBF9edVsUXAcDVVtdDUgnAl8IHFkdXw8KUl5fDkgRM2gIEmtIFVpKAxVtOHsUM184G2sWbURsVApfAR8XA2sLSw8cWA8LUw1ZCElHAmhdTAxGW1YBUlxtCkoWB2Y4" target="_blank">
|
||||
<img src="https://code-thinking-1253855093.file.myqcloud.com/pics/20211213180559.png" width="400"/>
|
||||
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
|
||||
<img src="https://code-thinking-1253855093.file.myqcloud.com/pics/20221015160559.png" width="800"/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
|
||||
# LeetCode 刷题攻略
|
||||
|
||||
## 刷题攻略的背景
|
||||
|
@ -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<int> 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。
|
||||
|
||||
|
@ -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呢,因为包括起始位置,我们要是一个左闭的集合。
|
||||
|
||||
|
@ -20,6 +20,11 @@
|
||||
|
||||

|
||||
|
||||
# 视频讲解
|
||||
|
||||
**《代码随想录》算法视频公开课:[你对二叉搜索树了解的还不够! | LeetCode:98.验证二叉搜索树](https://www.bilibili.com/video/BV18P411n7Q4),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
|
||||
|
||||
|
||||
# 思路
|
||||
|
||||
要知道中序遍历下,输出的二叉搜索树节点的数值是有序序列。
|
||||
|
@ -31,9 +31,17 @@
|
||||
|
||||
进入正题:
|
||||
|
||||
题目中说要转换为一棵高度平衡二叉搜索树。这和转换为一棵普通二叉搜索树有什么差别呢?
|
||||
题目中说要转换为一棵高度平衡二叉搜索树。为什么强调要平衡呢?
|
||||
|
||||
其实这里不用强调平衡二叉搜索树,数组构造二叉树,构成平衡树是自然而然的事情,因为大家默认都是从数组中间位置取值作为节点元素,一般不会随机取,**所以想构成不平衡的二叉树是自找麻烦**。
|
||||
因为只要给我们一个有序数组,如果强调平衡,都可以以线性结构来构造二叉搜索树。
|
||||
|
||||
例如 有序数组[-10,-3,0,5,9] 可以就可以构造成这样的二叉搜索树,如图。
|
||||
|
||||

|
||||
|
||||
上图中,是符合二叉搜索树的特性吧,如果要这么做的话,是不是本题意义就不大了,所以才强调是平衡二叉搜索树。
|
||||
|
||||
其实数组构造二叉树,构成平衡树是自然而然的事情,因为大家默认都是从数组中间位置取值作为节点元素,一般不会随机取。**所以想构成不平衡的二叉树是自找麻烦**。
|
||||
|
||||
|
||||
在[二叉树:构造二叉树登场!](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html)和[二叉树:构造一棵最大的二叉树](https://programmercarl.com/0654.最大二叉树.html)中其实已经讲过了,如果根据数组构造一棵二叉树。
|
||||
|
@ -89,19 +89,19 @@ C++代码如下:
|
||||
class Solution {
|
||||
public:
|
||||
int evalRPN(vector<string>& tokens) {
|
||||
stack<int> st;
|
||||
stack<long long> 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();
|
||||
|
@ -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 {
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -33,6 +33,11 @@
|
||||
* 所有节点的值都是唯一的。
|
||||
* p、q 为不同节点且均存在于给定的二叉树中。
|
||||
|
||||
# 算法公开课
|
||||
|
||||
**《代码随想录》算法视频公开课:[自底向上查找,有点难度! | LeetCode:236. 二叉树的最近公共祖先](https://www.bilibili.com/video/BV1jd4y1B7E2),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
|
||||
|
||||
|
||||
# 思路
|
||||
|
||||
遇到这个题目首先想的是要是能自底向上查找就好了,这样就可以找到公共祖先了。
|
||||
|
@ -33,6 +33,11 @@
|
||||
|
||||
进阶:你可以不使用额外的空间吗?(假设由递归产生的隐式调用栈的开销不被计算在内)
|
||||
|
||||
# 算法公开课
|
||||
|
||||
**《代码随想录》算法视频公开课:[不仅双指针,还有代码技巧可以惊艳到你! | LeetCode:501.二叉搜索树中的众数](https://www.bilibili.com/video/BV1fD4y117gp),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
|
||||
|
||||
|
||||
# 思路
|
||||
|
||||
这道题目呢,递归法我从两个维度来讲。
|
||||
|
@ -19,6 +19,11 @@
|
||||
|
||||
提示:树中至少有 2 个节点。
|
||||
|
||||
# 视频讲解
|
||||
|
||||
**《代码随想录》算法视频公开课:[二叉搜索树中,需要掌握如何双指针遍历!| LeetCode:530.二叉搜索树的最小绝对差](https://www.bilibili.com/video/BV1DD4y11779),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
|
||||
|
||||
|
||||
# 思路
|
||||
|
||||
题目中要求在二叉搜索树上任意两节点的差的绝对值的最小值。
|
||||
|
@ -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);
|
||||
|
@ -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<right):
|
||||
middle = round(left+(right-left)//2)
|
||||
if nums[middle] == target:
|
||||
return middle
|
||||
left, right = 0, len(nums)
|
||||
|
||||
while left < right:
|
||||
middle = (left + right) // 2
|
||||
|
||||
if nums[middle] < target:
|
||||
left = middle + 1
|
||||
elif nums[middle] > target:
|
||||
right=middle
|
||||
right = middle
|
||||
else:
|
||||
left=middle+1
|
||||
return -1
|
||||
return middle
|
||||
return -1
|
||||
```
|
||||
|
||||
**Go:**
|
||||
|
Reference in New Issue
Block a user