Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit cf4f84f

Browse files
Update
1 parent 398cf1a commit cf4f84f

File tree

2 files changed

+412
-24
lines changed

2 files changed

+412
-24
lines changed
Lines changed: 115 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,88 @@
1+
# 二叉树:以为使用了递归,其实还隐藏着回溯
12

2-
在上一面
3+
> 补充一波
34
5+
昨天的总结篇中[还在玩耍的你,该总结啦!(本周小结之二叉树)](https://mp.weixin.qq.com/s/QMBUTYnoaNfsVHlUADEzKg),有两处问题需要说明一波。
6+
7+
## 求相同的树
8+
9+
[还在玩耍的你,该总结啦!(本周小结之二叉树)](https://mp.weixin.qq.com/s/QMBUTYnoaNfsVHlUADEzKg)中求100.相同的树的代码中,我笔误贴出了 求对称树的代码了,细心的同学应该都发现了。
10+
11+
那么如下我再给出求100. 相同的树 的代码,如下:
12+
13+
```
14+
class Solution {
15+
public:
16+
bool compare(TreeNode* tree1, TreeNode* tree2) {
17+
if (tree1 == NULL && tree2 != NULL) return false;
18+
else if (tree1 != NULL && tree2 == NULL) return false;
19+
else if (tree1 == NULL && tree2 == NULL) return true;
20+
else if (tree1->val != tree2->val) return false; // 注意这里我没有使用else
21+
22+
// 此时就是:左右节点都不为空,且数值相同的情况
23+
// 此时才做递归,做下一层的判断
24+
bool compareLeft = compare(tree1->left, tree2->left); // 左子树:左、 右子树:左
25+
bool compareRight = compare(tree1->right, tree2->right); // 左子树:右、 右子树:右
26+
bool isSame = compareLeft && compareRight; // 左子树:中、 右子树:中(逻辑处理)
27+
return isSame;
28+
29+
}
30+
bool isSameTree(TreeNode* p, TreeNode* q) {
31+
return compare(p, q);
32+
}
33+
};
34+
```
35+
36+
以上的代码相对于:[二叉树:我对称么?](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg) 仅仅修改了变量的名字(为了符合判断相同树的语境)和 遍历的顺序。
37+
38+
大家应该会体会到:**认清[判断对称树](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg)本质之后, 对称树的代码 稍作修改 就可以直接用来AC 100.相同的树。**
39+
40+
## 递归中隐藏着回溯
41+
42+
[二叉树:找我的所有路径?](https://mp.weixin.qq.com/s/Osw4LQD2xVUnCJ-9jrYxJA)中我强调了本题其实是用到了回溯的,并且给出了第一个版本的代码,把回溯的过程充分的提现了出来。
43+
44+
如下的代码充分的体现出回溯:(257. 二叉树的所有路径)
445

546
```
647
class Solution {
748
private:
8-
void traversal(TreeNode* cur, string path, vector<string>& result) {
9-
path += to_string(cur->val); // 中
49+
50+
void traversal(TreeNode* cur, vector<int>& path, vector<string>& result) {
51+
path.push_back(cur->val);
52+
// 这才到了叶子节点
1053
if (cur->left == NULL && cur->right == NULL) {
11-
result.push_back(path);
54+
string sPath;
55+
for (int i = 0; i < path.size() - 1; i++) {
56+
sPath += to_string(path[i]);
57+
sPath += "->";
58+
}
59+
sPath += to_string(path[path.size() - 1]);
60+
result.push_back(sPath);
1261
return;
1362
}
14-
1563
if (cur->left) {
16-
path += "->";
17-
traversal(cur->left, path, result); // 左
64+
traversal(cur->left, path, result);
1865
path.pop_back(); // 回溯
19-
path.pop_back();
2066
}
2167
if (cur->right) {
22-
path += "->";
23-
traversal(cur->right, path, result); // 右
68+
traversal(cur->right, path, result);
2469
path.pop_back(); // 回溯
25-
path.pop_back();
2670
}
2771
}
2872
2973
public:
3074
vector<string> binaryTreePaths(TreeNode* root) {
3175
vector<string> result;
32-
string path;
76+
vector<int> path;
3377
if (root == NULL) return result;
3478
traversal(root, path, result);
3579
return result;
36-
3780
}
3881
};
3982
```
4083

41-
没有回溯了
84+
85+
如下为精简之后的递归代码:(257. 二叉树的所有路径)
4286
```
4387
class Solution {
4488
private:
@@ -48,15 +92,8 @@ private:
4892
result.push_back(path);
4993
return;
5094
}
51-
52-
if (cur->left) {
53-
path += "->";
54-
traversal(cur->left, path, result); // 左
55-
}
56-
if (cur->right) {
57-
path += "->";
58-
traversal(cur->right, path, result); // 右
59-
}
95+
if (cur->left) traversal(cur->left, path + "->", result); // 左 回溯就隐藏在这里
96+
if (cur->right) traversal(cur->right, path + "->", result); // 右 回溯就隐藏在这里
6097
}
6198
6299
public:
@@ -66,7 +103,61 @@ public:
66103
if (root == NULL) return result;
67104
traversal(root, path, result);
68105
return result;
69-
70106
}
71107
};
72108
```
109+
110+
上面的代码,大家貌似感受不到回溯了,其实**回溯就隐藏在traversal(cur->left, path + "->", result);中的 path + "->"。 每次函数调用完,path依然是没有加上"->" 的,这就是回溯了。**
111+
112+
为了把这份精简代码的回溯过程展现出来,大家可以试一试把:
113+
114+
```
115+
if (cur->left) traversal(cur->left, path + "->", result); // 左 回溯就隐藏在这里
116+
```
117+
118+
改成如下代码:
119+
120+
```
121+
path += "->";
122+
traversal(cur->left, path, result); // 左
123+
```
124+
125+
即:
126+
127+
```
128+
129+
if (cur->left) {
130+
path += "->";
131+
traversal(cur->left, path, result); // 左
132+
}
133+
if (cur->right) {
134+
path += "->";
135+
traversal(cur->right, path, result); // 右
136+
}
137+
```
138+
139+
此时就没有回溯了,这个代码就是通过不了的了。
140+
141+
如果想把回溯加上,就要 在上面代码的基础上,加上回溯,就可以AC了。
142+
143+
```
144+
if (cur->left) {
145+
path += "->";
146+
traversal(cur->left, path, result); // 左
147+
path.pop_back(); // 回溯
148+
path.pop_back();
149+
}
150+
if (cur->right) {
151+
path += "->";
152+
traversal(cur->right, path, result); // 右
153+
path.pop_back(); // 回溯
154+
path.pop_back();
155+
}
156+
```
157+
158+
**大家应该可以感受出来,如果把 `path + "->"`作为函数参数就是可以的,因为并有没有改变path的数值,执行完递归函数之后,path依然是之前的数值(相当于回溯了)**
159+
160+
如果有点遗忘了,建议把这篇[二叉树:找我的所有路径?](https://mp.weixin.qq.com/s/Osw4LQD2xVUnCJ-9jrYxJA)在仔细看一下,然后再看这里的总结,相信会豁然开朗。
161+
162+
这里我尽量把逻辑的每一个细节都抠出来展现了,希望对大家有所帮助!
163+

0 commit comments

Comments
 (0)