diff --git a/README.md b/README.md
index 3f432a75..18d36d58 100644
--- a/README.md
+++ b/README.md
@@ -94,6 +94,7 @@
* [二叉树:我有多少个节点?](https://mp.weixin.qq.com/s/2_eAjzw-D0va9y4RJgSmXw)
* [二叉树:我平衡么?](https://mp.weixin.qq.com/s/isUS-0HDYknmC0Rr4R8mww)
* [二叉树:找我的所有路径?](https://mp.weixin.qq.com/s/Osw4LQD2xVUnCJ-9jrYxJA)
+ * [还在玩耍的你,该总结啦!(本周小结之二叉树)](https://mp.weixin.qq.com/s/QMBUTYnoaNfsVHlUADEzKg)
(持续更新中....)
diff --git a/pics/404.左叶子之和1.png b/pics/404.左叶子之和1.png
new file mode 100644
index 00000000..8c050e04
Binary files /dev/null and b/pics/404.左叶子之和1.png differ
diff --git a/problems/0100.相同的树.md b/problems/0100.相同的树.md
index 6a771117..b596010a 100644
--- a/problems/0100.相同的树.md
+++ b/problems/0100.相同的树.md
@@ -68,40 +68,38 @@ else if (tree1->val != tree2->val) return false; // 注意这里我没有
代码如下:
```
-bool outside = compare(tree1->left, tree2->right); // 左子树:左、 右子树:左
-bool inside = compare(tree1->right, tree2->left); // 左子树:右、 右子树:右
+bool outside = compare(tree1->left, tree2->left); // 左子树:左、 右子树:左
+bool inside = compare(tree1->right, tree2->right); // 左子树:右、 右子树:右
bool isSame = outside && inside; // 左子树:中、 右子树:中(逻辑处理)
return isSame;
```
--------------------------------------------------------------- 写到这
最后递归的C++整体代码如下:
```
class Solution {
public:
- bool compare(TreeNode* left, TreeNode* right) {
- // 首先排除空节点的情况
- if (left == NULL && right != NULL) return false;
- else if (left != NULL && right == NULL) return false;
- else if (left == NULL && right == NULL) return true;
- // 排除了空节点,再排除数值不相同的情况
- else if (left->val != right->val) return false;
+ bool compare(TreeNode* tree1, TreeNode* tree2) {
+ if (tree1 == NULL && tree2 != NULL) return false;
+ else if (tree1 != NULL && tree2 == NULL) return false;
+ else if (tree1 == NULL && tree2 == NULL) return true;
+ else if (tree1->val != tree2->val) return false; // 注意这里我没有使用else
// 此时就是:左右节点都不为空,且数值相同的情况
// 此时才做递归,做下一层的判断
- bool outside = compare(left->left, right->right); // 左子树:左、 右子树:左
- bool inside = compare(left->right, right->left); // 左子树:右、 右子树:右
- bool isSame = outside && inside; // 左子树:中、 右子树:中 (逻辑处理)
+ bool outside = compare(tree1->left, tree2->left); // 左子树:左、 右子树:左
+ bool inside = compare(tree1->right, tree2->right); // 左子树:右、 右子树:右
+ bool isSame = outside && inside; // 左子树:中、 右子树:中(逻辑处理)
return isSame;
}
- bool isSymmetric(TreeNode* root) {
- if (root == NULL) return true;
- return compare(root->left, root->right);
+ bool isSameTree(TreeNode* p, TreeNode* q) {
+ return compare(p, q);
}
};
```
+-------------------------------------------------------------- 写到这
+
**我给出的代码并不简洁,但是把每一步判断的逻辑都清楚的描绘出来了。**
如果上来就看网上各种简洁的代码,看起来真的很简单,但是很多逻辑都掩盖掉了,而题解可能也没有把掩盖掉的逻辑说清楚。
diff --git a/problems/0257.二叉树的所有路径.md b/problems/0257.二叉树的所有路径.md
index 3fcbe67d..1e083c78 100644
--- a/problems/0257.二叉树的所有路径.md
+++ b/problems/0257.二叉树的所有路径.md
@@ -207,8 +207,12 @@ public:
那么在如上代码中,**貌似没有看到回溯的逻辑,其实不然,回溯就隐藏在`traversal(cur->left, path + "->", result);`中的 `path + "->"`。** 每次函数调用完,path依然是没有加上"->" 的,这就是回溯了。
+
+
**综合以上,第二种递归的代码虽然精简但把很多重要的点隐藏在了代码细节里,第一种递归写法虽然代码多一些,但是把每一个逻辑处理都完整的展现了出来了。**
+
+
## 迭代法
至于非递归的方式,我们可以依然可以使用前序遍历的迭代方式来模拟遍历路径的过程,对该迭代方式不了解的同学,可以看文章[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg)和[二叉树:前中后序迭代方式的写法就不能统一一下么?](https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg)。
diff --git a/problems/0404.左叶子之和.md b/problems/0404.左叶子之和.md
index d1a17f7b..4d8d5f04 100644
--- a/problems/0404.左叶子之和.md
+++ b/problems/0404.左叶子之和.md
@@ -1,9 +1,19 @@
## 题目地址
https://leetcode-cn.com/problems/sum-of-left-leaves/
-## 思路
+> 有的题目就是
-首先要注意是判断左叶子呢,不是左子树,不要上来想着层序遍历。
+# 404.左叶子之和
+
+计算给定二叉树的所有左叶子之和。
+
+示例:
+
+
+
+# 思路
+
+**首先要注意是判断左叶子,不是二叉树左侧节点,所以不要上来想着层序遍历。**
因为题目中其实没有说清楚左叶子究竟是什么节点,那么我来给出左叶子的明确定义:**如果左节点不为空,且左节点没有左右孩子,那么这个节点就是左叶子**
@@ -13,42 +23,99 @@ https://leetcode-cn.com/problems/sum-of-left-leaves/
**其实是0,因为这棵树根本没有左叶子!**
-那么判断左叶子,如果**判断当前节点是不是左叶子是无法判断的,必须要通过节点的父节点来判断其左孩子是不是左叶子。**
+那么**判断当前节点是不是左叶子是无法判断的,必须要通过节点的父节点来判断其左孩子是不是左叶子。**
-判断的根据如下:
+
+如果该节点的左节点不为空,该节点的左节点的左节点为空,该节点的左节点的右节点为空,则找到了一个左叶子,判断代码如下:
```
- if (node->left != NULL && node->left->left == NULL && node->left->right == NULL) {
- sum = node->left->val;
- }
+if (node->left != NULL && node->left->left == NULL && node->left->right == NULL) {
+ 左叶子节点处理逻辑
+}
```
-递归写法代码如下:
+## 递归法
-## 递归C++代码
+递归的遍历顺序为后序遍历(左右中),是因为要通过递归函数的返回值来累加求取左叶子数值之和。。
+
+递归三部曲:
+
+1. 确定递归函数的参数和返回值
+
+判断一个树的左叶子节点之和,那么一定要传入树的根节点,递归函数的返回值为数值之和,所以为int
+
+使用题目中给出的函数就可以了。
+
+2. 确定终止条件
+
+依然是
+```
+if (root == NULL) return 0;
+```
+
+3. 确定单层递归的逻辑
+
+当遇到左叶子节点的时候,记录数值,然后通过递归求取左子树左叶子之和,和 右子树左叶子之和,相加便是整个树的左叶子之和。
+
+代码如下:
+
+```
+int leftValue = sumOfLeftLeaves(root->left); // 左
+int rightValue = sumOfLeftLeaves(root->right); // 右
+ // 中
+int midValue = 0;
+if (root->left && !root->left->left && !root->left->right) {
+ midValue = root->left->val;
+}
+int sum = midValue + leftValue + rightValue;
+return sum;
+
+```
+
+
+整体递归代码如下:
```
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
if (root == NULL) return 0;
- int sum = 0;
- if (root->left != NULL && root->left->left == NULL && root->left->right == NULL) {
- sum = root->left->val;
+
+ int leftValue = sumOfLeftLeaves(root->left); // 左
+ int rightValue = sumOfLeftLeaves(root->right); // 右
+ // 中
+ int midValue = 0;
+ if (root->left && !root->left->left && !root->left->right) { // 中
+ midValue = root->left->val;
}
- return sum + sumOfLeftLeaves(root->left) + sumOfLeftLeaves(root->right);
+ int sum = midValue + leftValue + rightValue;
+ return sum;
}
};
```
-递归的过程其实就是二叉树的前序遍历,那么写过二叉树的同学都知道,既然是二叉树的前序遍历,能写出递归,就能写出非递归。
+以上代码精简之后如下:
-如果对二叉树的各种递归和非递归的写法不熟悉,可以看我的这个题解:
-[彻底吃透二叉树的前中后序递归法和迭代法!!](https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/che-di-chi-tou-er-cha-shu-de-qian-zhong-hou-xu-d-2/)
+```
+class Solution {
+public:
+ int sumOfLeftLeaves(TreeNode* root) {
+ if (root == NULL) return 0;
+ int midValue = 0;
+ if (root->left != NULL && root->left->left == NULL && root->left->right == NULL) {
+ midValue = root->left->val;
+ }
+ return midValue + sumOfLeftLeaves(root->left) + sumOfLeftLeaves(root->right);
+ }
+};
+```
-那么非递归版本善良登场,判断条件都是一样的
+## 迭代法
-## 非递归C++代码
+
+本题使用了后序遍历啊,那么参考文章 [二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg)和[二叉树:前中后序迭代方式的写法就不能统一一下么?](https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg)中的写法,同样可以写出一个后序遍历的迭代法。
+
+判断条件都是一样的,代码如下:
```
@@ -70,8 +137,15 @@ public:
}
return result;
}
-
-
};
```
+# 总结
+
+这道题目要求左叶子之和,其实是比较绕的,因为不能判断本节点是不是左叶子节点。
+
+此时就要通过节点的父节点来判断其左孩子是不是左叶子了。
+
+**平时我们解二叉树的题目时,已经习惯了通过节点的左右孩子判断本节点的属性,而本题我们要通过节点的父节点判断本节点的属性。**
+
+希望通过这道题目,可以扩展大家对二叉树的解题思路。
diff --git a/problems/二叉树中递归带着回溯.md b/problems/二叉树中递归带着回溯.md
new file mode 100644
index 00000000..3cb00f24
--- /dev/null
+++ b/problems/二叉树中递归带着回溯.md
@@ -0,0 +1,72 @@
+
+在上一面
+
+
+```
+class Solution {
+private:
+ void traversal(TreeNode* cur, string path, vector& result) {
+ path += to_string(cur->val); // 中
+ if (cur->left == NULL && cur->right == NULL) {
+ result.push_back(path);
+ return;
+ }
+
+ if (cur->left) {
+ path += "->";
+ traversal(cur->left, path, result); // 左
+ path.pop_back(); // 回溯
+ path.pop_back();
+ }
+ if (cur->right) {
+ path += "->";
+ traversal(cur->right, path, result); // 右
+ path.pop_back(); // 回溯
+ path.pop_back();
+ }
+ }
+
+public:
+ vector binaryTreePaths(TreeNode* root) {
+ vector result;
+ string path;
+ if (root == NULL) return result;
+ traversal(root, path, result);
+ return result;
+
+ }
+};
+```
+
+没有回溯了
+```
+class Solution {
+private:
+ void traversal(TreeNode* cur, string path, vector& result) {
+ path += to_string(cur->val); // 中
+ if (cur->left == NULL && cur->right == NULL) {
+ result.push_back(path);
+ return;
+ }
+
+ if (cur->left) {
+ path += "->";
+ traversal(cur->left, path, result); // 左
+ }
+ if (cur->right) {
+ path += "->";
+ traversal(cur->right, path, result); // 右
+ }
+ }
+
+public:
+ vector binaryTreePaths(TreeNode* root) {
+ vector result;
+ string path;
+ if (root == NULL) return result;
+ traversal(root, path, result);
+ return result;
+
+ }
+};
+```