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

Commit 29f3c9e

Browse files
Update
1 parent a54fe17 commit 29f3c9e

File tree

3 files changed

+155
-2
lines changed

3 files changed

+155
-2
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@
6262
* [字符串:替换空格](https://mp.weixin.qq.com/s/t0A9C44zgM-RysAQV3GZpg)
6363
* [字符串:花式反转还不够!](https://mp.weixin.qq.com/s/X3qpi2v5RSp08mO-W5Vicw)
6464
* [字符串:反转个字符串还有这个用处?](https://mp.weixin.qq.com/s/PmcdiWSmmccHAONzU0ScgQ)
65-
* [字符串:KMP是时候上场了(一文读懂系列)](https://mp.weixin.qq.com/s/70OXnZ4Ez29CKRrUpVJmug)
65+
* [帮你把KMP算法学个通透!(理论篇)B站视频](https://www.bilibili.com/video/BV1PD4y1o7nd)
66+
* [帮你把KMP算法学个通透!(代码篇)B站视频](https://www.bilibili.com/video/BV1M5411j7Xx)
6667
* [字符串:都来看看KMP的看家本领!](https://mp.weixin.qq.com/s/Gk9FKZ9_FSWLEkdGrkecyg)
67-
* [字符串:听说你对KMP有这些疑问?](https://mp.weixin.qq.com/s/mqx6IM2AO4kLZwvXdPtEeQ)
6868
* [字符串:KMP算法还能干这个!](https://mp.weixin.qq.com/s/lR2JPtsQSR2I_9yHbBmBuQ)
6969
* [字符串:前缀表不右移,难道就写不出KMP了?](https://mp.weixin.qq.com/s/p3hXynQM2RRROK5c6X7xfw)
7070
* [字符串:总结篇!](https://mp.weixin.qq.com/s/gtycjyDtblmytvBRFlCZJg)
59.5 KB
Loading
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
2+
## 思路
3+
4+
本题和[113.路径总和II](https://github.com/youngyangyang04/leetcode-master/blob/master/problems/0113.%E8%B7%AF%E5%BE%84%E6%80%BB%E5%92%8CII.md)是类似的思路,做完这道题,可以顺便把[113.路径总和II](https://github.com/youngyangyang04/leetcode-master/blob/master/problems/0113.%E8%B7%AF%E5%BE%84%E6%80%BB%E5%92%8CII.md)[112.路径总和](https://github.com/youngyangyang04/leetcode/blob/master/problems/0112.路径总和.md) 做了。
5+
6+
结合112.路径总和 和 113.路径总和II,我在讲了[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg),如果大家对二叉树递归函数什么时候需要返回值很迷茫,可以看一下。
7+
8+
接下来在看本题,就简单多了,本题其实需要使用回溯,但一些同学可能都不知道自己用了回溯,在[二叉树:以为使用了递归,其实还隐藏着回溯](https://mp.weixin.qq.com/s/ivLkHzWdhjQQD1rQWe6zWA)中,我详细讲解了二叉树的递归中,如何使用了回溯。
9+
10+
接下来我们来看题:
11+
12+
首先思路很明确,就是要遍历整个树把更节点到叶子节点组成的数字相加。
13+
14+
那么先按递归三部曲来分析:
15+
16+
### 递归三部曲
17+
18+
如果对递归三部曲不了解的话,可以看这里:[二叉树:前中后递归详解](https://mp.weixin.qq.com/s/PwVIfxDlT3kRgMASWAMGhA)
19+
20+
* 确定递归函数返回值及其参数
21+
22+
这里我们要遍历整个二叉树,且需要要返回值做逻辑处理,所有返回值为void,在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg)中,详细讲解了返回值问题。
23+
24+
参数只需要把根节点传入,此时还需要定义两个全局遍历,一个是result,记录最终结果,一个是vector<int> path。
25+
26+
**为什么用vector类型(就是数组)呢? 因为用vector方便我们做回溯!**
27+
28+
所以代码如下:
29+
30+
```
31+
int result;
32+
vector<int> path;
33+
void traversal(TreeNode* cur)
34+
```
35+
36+
* 确定终止条件
37+
38+
递归什么时候终止呢?
39+
40+
当然是遇到叶子节点,此时要收集结果了,通知返回本层递归,因为单条路径的结果使用vector,我们需要一个函数vectorToInt把vector转成int。
41+
42+
终止条件代码如下:
43+
44+
```
45+
if (!cur->left && !cur->right) { // 遇到了叶子节点
46+
result += vectorToInt(path);
47+
return;
48+
}
49+
```
50+
51+
这里vectorToInt函数就是把数组转成int,代码如下:
52+
53+
```
54+
int vectorToInt(const vector<int>& vec) {
55+
int sum = 0;
56+
for (int i = 0; i < vec.size(); i++) {
57+
sum = sum * 10 + vec[i];
58+
}
59+
return sum;
60+
}
61+
```
62+
63+
64+
* 确定递归单层逻辑
65+
66+
本题其实采用前中后序都不无所谓, 因为也没有中间几点的处理逻辑。
67+
68+
这里主要是当左节点不为空,path收集路径,并递归左孩子,右节点同理。
69+
70+
**但别忘了回溯**
71+
72+
如图:
73+
74+
75+
<img src='../pics/129.求根到叶子节点数字之和.png' width=600> </img></div>
76+
77+
代码如下:
78+
79+
```
80+
// 中
81+
if (cur->left) { // 左 (空节点不遍历)
82+
path.push_back(cur->left->val);
83+
traversal(cur->left); // 递归
84+
path.pop_back(); // 回溯
85+
}
86+
if (cur->right) { // 右 (空节点不遍历)
87+
path.push_back(cur->right->val);
88+
traversal(cur->right); // 递归
89+
path.pop_back(); // 回溯
90+
}
91+
```
92+
93+
这里要注意回溯和递归要永远在一起,一个递归,对应一个回溯,是一对一的关系,有的同学写成如下代码:
94+
95+
```
96+
if (cur->left) { // 左 (空节点不遍历)
97+
path.push_back(cur->left->val);
98+
traversal(cur->left); // 递归
99+
}
100+
if (cur->right) { // 右 (空节点不遍历)
101+
path.push_back(cur->right->val);
102+
traversal(cur->right); // 递归
103+
}
104+
path.pop_back(); // 回溯
105+
```
106+
**把回溯放在花括号外面了,世界上最遥远的距离,是你在花括号里,而我在花括号外!** 这就不对了。
107+
108+
### 整体C++代码
109+
110+
关键逻辑分析完了,整体C++代码如下:
111+
112+
```
113+
class Solution {
114+
private:
115+
int result;
116+
vector<int> path;
117+
// 把vector转化为int
118+
int vectorToInt(const vector<int>& vec) {
119+
int sum = 0;
120+
for (int i = 0; i < vec.size(); i++) {
121+
sum = sum * 10 + vec[i];
122+
}
123+
return sum;
124+
}
125+
// 递归函数不需要返回值,因为我们要遍历整个树
126+
void traversal(TreeNode* cur) {
127+
if (!cur->left && !cur->right) { // 遇到了叶子节点
128+
result += vectorToInt(path);
129+
return;
130+
}
131+
132+
if (cur->left) { // 左 (空节点不遍历)
133+
path.push_back(cur->left->val);
134+
traversal(cur->left); // 递归
135+
path.pop_back(); // 回溯
136+
}
137+
if (cur->right) { // 右 (空节点不遍历)
138+
path.push_back(cur->right->val);
139+
traversal(cur->right); // 递归
140+
path.pop_back(); // 回溯
141+
}
142+
return ;
143+
}
144+
public:
145+
int sumNumbers(TreeNode* root) {
146+
path.clear();
147+
if (root == nullptr) return 0;
148+
path.push_back(root->val);
149+
traversal(root);
150+
return result;
151+
}
152+
};
153+
```

0 commit comments

Comments
 (0)