diff --git a/problems/0098.验证二叉搜索树.md b/problems/0098.验证二叉搜索树.md
index cba450e5..727144d5 100644
--- a/problems/0098.验证二叉搜索树.md
+++ b/problems/0098.验证二叉搜索树.md
@@ -87,7 +87,7 @@ public:
写出了类似这样的代码:
-```
+```CPP
if (root->val > root->left->val && root->val < root->right->val) {
return true;
} else {
@@ -95,7 +95,7 @@ if (root->val > root->left->val && root->val < root->right->val) {
}
```
-**我们要比较的是 左子树所有节点小于中间节点,右子树所有节点大于中间节点。**所以以上代码的判断逻辑是错误的。
+**我们要比较的是 左子树所有节点小于中间节点,右子树所有节点大于中间节点**。所以以上代码的判断逻辑是错误的。
例如: [10,5,15,null,null,6,20] 这个case:
@@ -125,7 +125,7 @@ if (root->val > root->left->val && root->val < root->right->val) {
代码如下:
-```
+```CPP
long long maxVal = LONG_MIN; // 因为后台测试数据中有int最小值
bool isValidBST(TreeNode* root)
```
@@ -138,7 +138,7 @@ bool isValidBST(TreeNode* root)
代码如下:
-```
+```CPP
if (root == NULL) return true;
```
@@ -148,7 +148,7 @@ if (root == NULL) return true;
代码如下:
-```
+```CPP
bool left = isValidBST(root->left); // 左
// 中序遍历,验证遍历的元素是不是从小到大
diff --git a/problems/0104.二叉树的最大深度.md b/problems/0104.二叉树的最大深度.md
index 392a3778..2bcc9c5c 100644
--- a/problems/0104.二叉树的最大深度.md
+++ b/problems/0104.二叉树的最大深度.md
@@ -5,11 +5,6 @@
参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
-看完本篇可以一起做了如下两道题目:
-
-* 104.二叉树的最大深度
-* 559.n叉树的最大深度
-
# 104.二叉树的最大深度
[力扣题目链接](https://leetcode.cn/problems/maximum-depth-of-binary-tree/)
@@ -27,6 +22,16 @@
返回它的最大深度 3 。
+# 思路
+
+看完本篇可以一起做了如下两道题目:
+
+* 104.二叉树的最大深度
+* 559.n叉树的最大深度
+
+《代码随想录》算法视频公开课:[二叉树的高度和深度有啥区别?究竟用什么遍历顺序?很多录友搞不懂 | 104.二叉树的最大深度](https://www.bilibili.com/video/BV1Gd4y1V75u),相信结合视频在看本篇题解,更有助于大家对本题的理解。
+
+
## 递归法
本题可以使用前序(中左右),也可以使用后序遍历(左右中),使用前序求的就是深度,使用后序求的是高度。
diff --git a/problems/0110.平衡二叉树.md b/problems/0110.平衡二叉树.md
index 5bdd4f1b..a87b64fc 100644
--- a/problems/0110.平衡二叉树.md
+++ b/problems/0110.平衡二叉树.md
@@ -31,8 +31,10 @@
返回 false 。
-# 题外话
+**《代码随想录》算法视频公开课:[后序遍历求高度,高度判断是否平衡 | LeetCode:110.平衡二叉树](https://www.bilibili.com/video/BV1Ug411S7my),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
+
+## 题外话
咋眼一看这道题目和[104.二叉树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html)很像,其实有很大区别。
@@ -113,9 +115,9 @@ public:
};
```
-# 本题思路
+## 本题思路
-## 递归
+### 递归
此时大家应该明白了既然要求比较高度,必然是要后序遍历。
@@ -225,7 +227,7 @@ public:
};
```
-## 迭代
+### 迭代
在[104.二叉树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html)中我们可以使用层序遍历来求深度,但是就不能直接用层序遍历来求高度了,这就体现出求高度和求深度的不同。
@@ -342,7 +344,7 @@ public:
因为对于回溯算法已经是非常复杂的递归了,如果在用迭代的话,就是自己给自己找麻烦,效率也并不一定高。
-# 总结
+## 总结
通过本题可以了解求二叉树深度 和 二叉树高度的差异,求深度适合用前序遍历,而求高度适合用后序遍历。
@@ -351,9 +353,9 @@ public:
但是递归方式是一定要掌握的!
-# 其他语言版本
+## 其他语言版本
-## Java
+### Java
```Java
class Solution {
@@ -494,7 +496,7 @@ class Solution {
}
```
-## Python
+### Python
递归法:
```python
@@ -554,7 +556,7 @@ class Solution:
```
-## Go
+### Go
```Go
func isBalanced(root *TreeNode) bool {
if root==nil{
@@ -590,7 +592,7 @@ func abs(a int)int{
}
```
-## JavaScript
+### JavaScript
递归法:
```javascript
var isBalanced = function(root) {
@@ -658,7 +660,7 @@ var isBalanced = function (root) {
};
```
-## TypeScript
+### TypeScript
```typescript
// 递归法
@@ -676,7 +678,7 @@ function isBalanced(root: TreeNode | null): boolean {
};
```
-## C
+### C
递归法:
```c
@@ -780,7 +782,7 @@ bool isBalanced(struct TreeNode* root){
}
```
-## Swift:
+### Swift:
>递归
```swift
diff --git a/problems/0111.二叉树的最小深度.md b/problems/0111.二叉树的最小深度.md
index 3c32f620..403027e4 100644
--- a/problems/0111.二叉树的最小深度.md
+++ b/problems/0111.二叉树的最小深度.md
@@ -27,6 +27,9 @@
# 思路
+《代码随想录》算法视频公开课:[看起来好像做过,一写就错! | LeetCode:111.二叉树的最小深度](https://www.bilibili.com/video/BV1QD4y1B7e2),相信结合视频在看本篇题解,更有助于大家对本题的理解。
+
+
看完了这篇[104.二叉树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html),再来看看如何求最小深度。
直觉上好像和求最大深度差不多,其实还是差不少的。
diff --git a/problems/0112.路径总和.md b/problems/0112.路径总和.md
index d4cb5190..d8d4e2f8 100644
--- a/problems/0112.路径总和.md
+++ b/problems/0112.路径总和.md
@@ -123,9 +123,9 @@ return false;
整体代码如下:
```cpp
-class solution {
+class Solution {
private:
- bool traversal(treenode* cur, int count) {
+ bool traversal(TreeNode* cur, int count) {
if (!cur->left && !cur->right && count == 0) return true; // 遇到叶子节点,并且计数为0
if (!cur->left && !cur->right) return false; // 遇到叶子节点直接返回
@@ -143,8 +143,8 @@ private:
}
public:
- bool haspathsum(treenode* root, int sum) {
- if (root == null) return false;
+ bool hasPathSum(TreeNode* root, int sum) {
+ if (root == NULL) return false;
return traversal(root, sum - root->val);
}
};
@@ -155,7 +155,7 @@ public:
```cpp
class solution {
public:
- bool haspathsum(treenode* root, int sum) {
+ bool hasPathSum(TreeNode* root, int sum) {
if (root == null) return false;
if (!root->left && !root->right && sum == root->val) {
return true;
@@ -176,7 +176,7 @@ public:
c++就我们用pair结构来存放这个栈里的元素。
-定义为:`pair` pair<节点指针,路径数值>
+定义为:`pair` pair<节点指针,路径数值>
这个为栈里的一个元素。
@@ -186,25 +186,25 @@ c++就我们用pair结构来存放这个栈里的元素。
class solution {
public:
- bool haspathsum(treenode* root, int sum) {
+ bool haspathsum(TreeNode* root, int sum) {
if (root == null) return false;
// 此时栈里要放的是pair<节点指针,路径数值>
- stack> st;
- st.push(pair(root, root->val));
+ stack> st;
+ st.push(pair(root, root->val));
while (!st.empty()) {
- pair node = st.top();
+ pair node = st.top();
st.pop();
// 如果该节点是叶子节点了,同时该节点的路径数值等于sum,那么就返回true
if (!node.first->left && !node.first->right && sum == node.second) return true;
// 右节点,压进去一个节点的时候,将该节点的路径数值也记录下来
if (node.first->right) {
- st.push(pair(node.first->right, node.second + node.first->right->val));
+ st.push(pair(node.first->right, node.second + node.first->right->val));
}
// 左节点,压进去一个节点的时候,将该节点的路径数值也记录下来
if (node.first->left) {
- st.push(pair(node.first->left, node.second + node.first->left->val));
+ st.push(pair(node.first->left, node.second + node.first->left->val));
}
}
return false;
diff --git a/problems/0222.完全二叉树的节点个数.md b/problems/0222.完全二叉树的节点个数.md
index 4057053e..dc037f0a 100644
--- a/problems/0222.完全二叉树的节点个数.md
+++ b/problems/0222.完全二叉树的节点个数.md
@@ -32,6 +32,8 @@
# 思路
+《代码随想录》算法视频公开课:[要理解普通二叉树和完全二叉树的区别! | LeetCode:222.完全二叉树节点的数量](https://www.bilibili.com/video/BV1eW4y1B7pD),相信结合视频在看本篇题解,更有助于大家对本题的理解。
+
本篇给出按照普通二叉树的求法以及利用完全二叉树性质的求法。
## 普通二叉树
diff --git a/problems/0257.二叉树的所有路径.md b/problems/0257.二叉树的所有路径.md
index 0dc9a09b..579c214f 100644
--- a/problems/0257.二叉树的所有路径.md
+++ b/problems/0257.二叉树的所有路径.md
@@ -20,6 +20,8 @@
# 思路
+**《代码随想录》算法视频公开课:[递归中带着回溯,你感受到了没?| LeetCode:257. 二叉树的所有路径](https://www.bilibili.com/video/BV1ZG411G7Dh),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
+
这道题目要求从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径。
在这道题目中将第一次涉及到回溯,因为我们要把路径记录下来,需要回溯来回退一一个路径在进入另一个路径。
diff --git a/problems/0404.左叶子之和.md b/problems/0404.左叶子之和.md
index 2d522f41..12a2881e 100644
--- a/problems/0404.左叶子之和.md
+++ b/problems/0404.左叶子之和.md
@@ -17,6 +17,9 @@
# 思路
+**《代码随想录》算法视频公开课:[二叉树的题目中,总有一些规则让你找不到北 | LeetCode:404.左叶子之和](https://www.bilibili.com/video/BV1GY4y1K7z8),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
+
+
**首先要注意是判断左叶子,不是二叉树左侧节点,所以不要上来想着层序遍历。**
因为题目中其实没有说清楚左叶子究竟是什么节点,那么我来给出左叶子的明确定义:**节点A的左孩子不为空,且左孩子的左右孩子都为空(说明是叶子节点),那么A节点的左孩子为左叶子节点**
diff --git a/problems/0501.二叉搜索树中的众数.md b/problems/0501.二叉搜索树中的众数.md
index 671d8061..ad6577dd 100644
--- a/problems/0501.二叉搜索树中的众数.md
+++ b/problems/0501.二叉搜索树中的众数.md
@@ -72,7 +72,7 @@ void searchBST(TreeNode* cur, unordered_map& map) { // 前序遍历
代码如下:
-```
+```CPP
bool static cmp (const pair& a, const pair& b) {
return a.second > b.second; // 按照频率从大到小排序
}
@@ -169,7 +169,7 @@ void searchBST(TreeNode* cur) {
代码如下:
-```
+```CPP
if (pre == NULL) { // 第一个节点
count = 1; // 频率为1
} else if (pre->val == cur->val) { // 与前一个节点数值相同
@@ -194,7 +194,7 @@ pre = cur; // 更新上一个节点
如果 频率count 等于 maxCount(最大频率),当然要把这个元素加入到结果集中(以下代码为result数组),代码如下:
-```
+```CPP
if (count == maxCount) { // 如果和最大值相同,放进result中
result.push_back(cur->val);
}
@@ -206,7 +206,7 @@ if (count == maxCount) { // 如果和最大值相同,放进result中
频率count 大于 maxCount的时候,不仅要更新maxCount,而且要清空结果集(以下代码为result数组),因为结果集之前的元素都失效了。
-```
+```CPP
if (count > maxCount) { // 如果计数大于最大值
maxCount = count; // 更新最大频率
result.clear(); // 很关键的一步,不要忘记清空result,之前result里的元素都失效了
diff --git a/problems/0513.找树左下角的值.md b/problems/0513.找树左下角的值.md
index 817c22c9..2218a549 100644
--- a/problems/0513.找树左下角的值.md
+++ b/problems/0513.找树左下角的值.md
@@ -41,7 +41,7 @@
所以要找深度最大的叶子节点。
-那么如果找最左边的呢?可以使用前序遍历,这样才先优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值。
+那么如果找最左边的呢?可以使用前序遍历(当然中序,后序都可以,因为本题没有 中间节点的处理逻辑,只要左优先就行),保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值。
递归三部曲:
@@ -49,25 +49,16 @@
参数必须有要遍历的树的根节点,还有就是一个int型的变量用来记录最长深度。 这里就不需要返回值了,所以递归函数的返回类型为void。
-本题还需要类里的两个全局变量,maxLen用来记录最大深度,maxleftValue记录最大深度最左节点的数值。
+本题还需要类里的两个全局变量,maxLen用来记录最大深度,result记录最大深度最左节点的数值。
代码如下:
```CPP
-int maxLen = INT_MIN; // 全局变量 记录最大深度
-int maxleftValue; // 全局变量 最大深度最左节点的数值
-void traversal(TreeNode* root, int leftLen)
+int maxDepth = INT_MIN; // 全局变量 记录最大深度
+int result; // 全局变量 最大深度最左节点的数值
+void traversal(TreeNode* root, int depth)
```
-有的同学可能疑惑,为啥不能递归函数的返回值返回最长深度呢?
-
-其实很多同学都对递归函数什么时候要有返回值,什么时候不能有返回值很迷茫。
-
-**如果需要遍历整棵树,递归函数就不能有返回值。如果需要遍历某一条固定路线,递归函数就一定要有返回值!**
-
-初学者可能对这个结论不太理解,别急,后面我会安排一道题目专门讲递归函数的返回值问题。这里大家暂时先了解一下。
-
-本题我们是要遍历整个树找到最深的叶子节点,需要遍历整棵树,所以递归函数没有返回值。
2. 确定终止条件
@@ -77,9 +68,9 @@ void traversal(TreeNode* root, int leftLen)
```CPP
if (root->left == NULL && root->right == NULL) {
- if (leftLen > maxLen) {
- maxLen = leftLen; // 更新最大深度
- maxleftValue = root->val; // 最大深度最左面的数值
+ if (depth > maxDepth) {
+ maxDepth = depth; // 更新最大深度
+ result = root->val; // 最大深度最左面的数值
}
return;
}
@@ -92,14 +83,14 @@ if (root->left == NULL && root->right == NULL) {
```CPP
// 中
if (root->left) { // 左
- leftLen++; // 深度加一
- traversal(root->left, leftLen);
- leftLen--; // 回溯,深度减一
+ depth++; // 深度加一
+ traversal(root->left, depth);
+ depth--; // 回溯,深度减一
}
if (root->right) { // 右
- leftLen++; // 深度加一
- traversal(root->right, leftLen);
- leftLen--; // 回溯,深度减一
+ depth++; // 深度加一
+ traversal(root->right, depth);
+ depth--; // 回溯,深度减一
}
return;
```
@@ -109,31 +100,31 @@ return;
```CPP
class Solution {
public:
- int maxLen = INT_MIN;
- int maxleftValue;
- void traversal(TreeNode* root, int leftLen) {
+ int maxDepth = INT_MIN;
+ int result;
+ void traversal(TreeNode* root, int depth) {
if (root->left == NULL && root->right == NULL) {
- if (leftLen > maxLen) {
- maxLen = leftLen;
- maxleftValue = root->val;
+ if (depth > maxDepth) {
+ maxDepth = depth;
+ result = root->val;
}
return;
}
if (root->left) {
- leftLen++;
- traversal(root->left, leftLen);
- leftLen--; // 回溯
+ depth++;
+ traversal(root->left, depth);
+ depth--; // 回溯
}
if (root->right) {
- leftLen++;
- traversal(root->right, leftLen);
- leftLen--; // 回溯
+ depth++;
+ traversal(root->right, depth);
+ depth--; // 回溯
}
return;
}
int findBottomLeftValue(TreeNode* root) {
traversal(root, 0);
- return maxleftValue;
+ return result;
}
};
```
@@ -143,27 +134,27 @@ public:
```CPP
class Solution {
public:
- int maxLen = INT_MIN;
- int maxleftValue;
- void traversal(TreeNode* root, int leftLen) {
+ int maxDepth = INT_MIN;
+ int result;
+ void traversal(TreeNode* root, int depth) {
if (root->left == NULL && root->right == NULL) {
- if (leftLen > maxLen) {
- maxLen = leftLen;
- maxleftValue = root->val;
+ if (depth > maxDepth) {
+ maxDepth = depth;
+ result = root->val;
}
return;
}
if (root->left) {
- traversal(root->left, leftLen + 1); // 隐藏着回溯
+ traversal(root->left, depth + 1); // 隐藏着回溯
}
if (root->right) {
- traversal(root->right, leftLen + 1); // 隐藏着回溯
+ traversal(root->right, depth + 1); // 隐藏着回溯
}
return;
}
int findBottomLeftValue(TreeNode* root) {
traversal(root, 0);
- return maxleftValue;
+ return result;
}
};
```
@@ -555,14 +546,14 @@ object Solution {
var maxLeftValue = 0
var maxLen = Int.MinValue
// 递归方法
- def traversal(node: TreeNode, leftLen: Int): Unit = {
+ def traversal(node: TreeNode, depth: Int): Unit = {
// 如果左右都为空并且当前深度大于最大深度,记录最左节点的值
- if (node.left == null && node.right == null && leftLen > maxLen) {
- maxLen = leftLen
+ if (node.left == null && node.right == null && depth > maxLen) {
+ maxLen = depth
maxLeftValue = node.value
}
- if (node.left != null) traversal(node.left, leftLen + 1)
- if (node.right != null) traversal(node.right, leftLen + 1)
+ if (node.left != null) traversal(node.left, depth + 1)
+ if (node.right != null) traversal(node.right, depth + 1)
}
traversal(root, 0) // 调用方法
maxLeftValue // return关键字可以省略
diff --git a/problems/0530.二叉搜索树的最小绝对差.md b/problems/0530.二叉搜索树的最小绝对差.md
index 809f500b..9611df99 100644
--- a/problems/0530.二叉搜索树的最小绝对差.md
+++ b/problems/0530.二叉搜索树的最小绝对差.md
@@ -77,7 +77,7 @@ public:
class Solution {
private:
int result = INT_MAX;
-TreeNode* pre;
+TreeNode* pre = NULL;
void traversal(TreeNode* cur) {
if (cur == NULL) return;
traversal(cur->left); // 左
diff --git a/problems/0700.二叉搜索树中的搜索.md b/problems/0700.二叉搜索树中的搜索.md
index a8dcc69f..22f009cb 100644
--- a/problems/0700.二叉搜索树中的搜索.md
+++ b/problems/0700.二叉搜索树中的搜索.md
@@ -41,7 +41,7 @@
代码如下:
-```
+```CPP
TreeNode* searchBST(TreeNode* root, int val)
```
@@ -49,7 +49,7 @@ TreeNode* searchBST(TreeNode* root, int val)
如果root为空,或者找到这个数值了,就返回root节点。
-```
+```CPP
if (root == NULL || root->val == val) return root;
```
@@ -63,20 +63,36 @@ if (root == NULL || root->val == val) return root;
代码如下:
-```
-if (root->val > val) return searchBST(root->left, val); // 注意这里加了return
-if (root->val < val) return searchBST(root->right, val);
-return NULL;
+```CPP
+TreeNode* result = NULL;
+if (root->val > val) result = searchBST(root->left, val);
+if (root->val < val) result = searchBST(root->right, val);
+return result;
```
-这里可能会疑惑,在递归遍历的时候,什么时候直接return 递归函数的返回值,什么时候不用加这个 return呢。
+很多录友写递归函数的时候 习惯直接写 `searchBST(root->left, val)`,却忘了 递归函数还有返回值。
-我们在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://programmercarl.com/0112.路径总和.html)中讲了,如果要搜索一条边,递归函数就要加返回值,这里也是一样的道理。
+递归函数的返回值是什么? 是 左子树如果搜索到了val,要将该节点返回。 如果不用一个变量将其接住,那么返回值不就没了。
-**因为搜索到目标节点了,就要立即return了,这样才是找到节点就返回(搜索某一条边),如果不加return,就是遍历整棵树了。**
+所以要 `result = searchBST(root->left, val)`。
整体代码如下:
+```CPP
+class Solution {
+public:
+ TreeNode* searchBST(TreeNode* root, int val) {
+ if (root == NULL || root->val == val) return root;
+ TreeNode* result = NULL;
+ if (root->val > val) result = searchBST(root->left, val);
+ if (root->val < val) result = searchBST(root->right, val);
+ return result;
+ }
+};
+```
+
+或者我们也可以这么写
+
```CPP
class Solution {
public:
@@ -89,6 +105,7 @@ public:
};
```
+
## 迭代法
一提到二叉树遍历的迭代法,可能立刻想起使用栈来模拟深度遍历,使用队列来模拟广度遍历。