34
34
35
35
<!-- 这里可写通用的实现逻辑 -->
36
36
37
- DFS 深度优先搜索
37
+ ** 方法一:哈希表 + 前缀和 + 递归**
38
+
39
+ 我们可以运用前缀和的思想,对二叉树进行递归遍历,同时用哈希表 $cnt$ 统计从根节点到当前节点的路径上各个前缀和出现的次数。
40
+
41
+ 我们设计一个递归函数 $dfs(node, s)$,表示当前遍历到的节点为 $node$,从根节点到当前节点的路径上的前缀和为 $s$。函数的返回值是统计以 $node$ 节点及其子树节点作为路径终点且路径和为 $sum$ 的路径数目。那么答案就是 $dfs(root, 0)$。
42
+
43
+ 函数 $dfs(node, s)$ 的递归过程如下:
44
+
45
+ - 如果当前节点 $node$ 为空,则返回 $0$。
46
+ - 计算从根节点到当前节点的路径上的前缀和 $s$。
47
+ - 用 $cnt[ s - sum] $ 表示以当前节点为路径终点且路径和为 $sum$ 的路径数目,其中 $cnt[ s - sum] $ 即为 $cnt$ 中前缀和为 $s - sum$ 的个数。
48
+ - 将前缀和 $s$ 的计数值加 $1$,即 $cnt[ s] = cnt[ s] + 1$。
49
+ - 递归地遍历当前节点的左右子节点,即调用函数 $dfs(node.left, s)$ 和 $dfs(node.right, s)$,并将它们的返回值相加。
50
+ - 在返回值计算完成以后,需要将当前节点的前缀和 $s$ 的计数值减 $1$,即执行 $cnt[ s] = cnt[ s] - 1$。
51
+ - 最后返回答案。
52
+
53
+ 时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是二叉树的节点个数。
38
54
39
55
<!-- tabs:start -->
40
56
41
57
### ** Python3**
42
58
43
59
<!-- 这里可写当前语言的特殊实现逻辑 -->
44
60
45
- 采用递归的思想,每递归到某个节点时:
46
-
47
- - 若` root.val-sum == 0 ` ,结果加 1
48
- - 考虑将此节点纳入或不纳入路径两种情况
61
+ ``` python
62
+ # Definition for a binary tree node.
63
+ # class TreeNode:
64
+ # def __init__(self, x):
65
+ # self.val = x
66
+ # self.left = None
67
+ # self.right = None
49
68
50
- 特殊情况:若此节点的父节点在路径中,此节点必纳入路径(路径不能断)
51
69
52
- ``` python
53
70
class Solution :
54
71
def pathSum (self , root : TreeNode, sum : int ) -> int :
55
- def dfs (root , sum , flag ):
56
- nonlocal ans
57
- if not root:
72
+ def dfs (root : TreeNode, s : int ):
73
+ if root is None :
58
74
return 0
59
- if sum - root.val == 0 :
60
- ans += 1
61
- if flag == 0 :
62
- dfs(root.left, sum , 0 )
63
- dfs(root.right, sum , 0 )
64
- dfs(root.left, sum - root.val, 1 )
65
- dfs(root.right, sum - root.val, 1 )
66
-
67
- if not root:
68
- return 0
69
- ans = 0
70
- dfs(root, sum , 0 )
71
- return ans
75
+ s += root.val
76
+ ans = cnt[s - sum ]
77
+ cnt[s] += 1
78
+ ans += dfs(root.left, s)
79
+ ans += dfs(root.right, s)
80
+ cnt[s] -= 1
81
+ return ans
82
+
83
+ cnt = Counter({0 : 1 })
84
+ return dfs(root, 0 )
72
85
```
73
86
74
87
### ** Java**
75
88
76
89
<!-- 这里可写当前语言的特殊实现逻辑 -->
77
90
78
- 使用到 2 个递归过程:
79
-
80
- - BFS:(traverse)遍历每个树节点;
81
- - DFS: 从每个树节点出发,节点求和,看是否能满足 sum。
82
-
83
- 需要注意,节点值有正有负,需要穷尽所有的可能路径。
84
-
85
91
``` java
92
+ /**
93
+ * Definition for a binary tree node.
94
+ * public class TreeNode {
95
+ * int val;
96
+ * TreeNode left;
97
+ * TreeNode right;
98
+ * TreeNode(int x) { val = x; }
99
+ * }
100
+ */
86
101
class Solution {
87
- int ans = 0 ;
102
+ private Map<Long , Integer > cnt = new HashMap<> ();
103
+ private int target;
104
+
88
105
public int pathSum (TreeNode root , int sum ) {
89
- traverse(root, sum);
90
- return ans;
106
+ cnt. put(0L , 1 );
107
+ target = sum;
108
+ return dfs(root, 0 );
91
109
}
92
110
93
- void traverse (TreeNode root , int sum ) {
94
- if (root == null ) return ;
95
- ans += dfs(root, sum, 0 );
96
- traverse(root. left, sum);
97
- traverse(root. right, sum);
111
+ private int dfs (TreeNode root , long s ) {
112
+ if (root == null ) {
113
+ return 0 ;
114
+ }
115
+ s += root. val;
116
+ int ans = cnt. getOrDefault(s - target, 0 );
117
+ cnt. merge(s, 1 , Integer :: sum);
118
+ ans += dfs(root. left, s);
119
+ ans += dfs(root. right, s);
120
+ cnt. merge(s, - 1 , Integer :: sum);
121
+ return ans;
98
122
}
123
+ }
124
+ ```
125
+
126
+ ### ** C++**
99
127
100
- // check if sum of path is sum.
101
- int dfs (TreeNode root , int sum , int cur ) {
102
- if (root == null ) return 0 ;
103
- cur += root. val;
104
- int res = 0 ;
105
- if (cur == sum) res++ ;
106
- res += dfs(root. left, sum, cur);
107
- res += dfs(root. right, sum, cur);
108
- return res;
128
+ ``` cpp
129
+ /* *
130
+ * Definition for a binary tree node.
131
+ * struct TreeNode {
132
+ * int val;
133
+ * TreeNode *left;
134
+ * TreeNode *right;
135
+ * TreeNode(int x) : val(x), left(NULL), right(NULL) {}
136
+ * };
137
+ */
138
+ class Solution {
139
+ public:
140
+ int pathSum(TreeNode* root, int sum) {
141
+ unordered_map<long long, int> cnt;
142
+ cnt[ 0] = 1;
143
+ function<int(TreeNode* , long long)> dfs = [ &] (TreeNode* root, long long s) {
144
+ if (!root) {
145
+ return 0;
146
+ }
147
+ s += root->val;
148
+ int ans = cnt[ s - sum] ;
149
+ ++cnt[ s] ;
150
+ ans += dfs(root->left, s);
151
+ ans += dfs(root->right, s);
152
+ --cnt[ s] ;
153
+ return ans;
154
+ };
155
+ return dfs(root, 0);
109
156
}
157
+ };
158
+ ```
159
+
160
+ ### **Go**
161
+
162
+ ```go
163
+ /**
164
+ * Definition for a binary tree node.
165
+ * type TreeNode struct {
166
+ * Val int
167
+ * Left *TreeNode
168
+ * Right *TreeNode
169
+ * }
170
+ */
171
+ func pathSum(root *TreeNode, sum int) int {
172
+ cnt := map[int]int{0: 1}
173
+ var dfs func(*TreeNode, int) int
174
+ dfs = func(root *TreeNode, s int) int {
175
+ if root == nil {
176
+ return 0
177
+ }
178
+ s += root.Val
179
+ ans := cnt[s-sum]
180
+ cnt[s]++
181
+ ans += dfs(root.Left, s)
182
+ ans += dfs(root.Right, s)
183
+ cnt[s]--
184
+ return ans
185
+ }
186
+ return dfs(root, 0)
110
187
}
111
188
```
112
189
@@ -127,23 +204,22 @@ class Solution {
127
204
* }
128
205
*/
129
206
130
- function dfs(root : TreeNode | null , sum : number ): number {
131
- let res = 0 ;
132
- if (root == null ) {
133
- return res ;
134
- }
135
- sum -= root .val ;
136
- if (sum === 0 ) {
137
- res ++ ;
138
- }
139
- return res + dfs (root .left , sum ) + dfs (root .right , sum );
140
- }
141
-
142
207
function pathSum(root : TreeNode | null , sum : number ): number {
143
- if (root == null ) {
144
- return 0 ;
145
- }
146
- return dfs (root , sum ) + pathSum (root .left , sum ) + pathSum (root .right , sum );
208
+ const cnt: Map <number , number > = new Map ();
209
+ cnt .set (0 , 1 );
210
+ const dfs = (root : TreeNode | null , s : number ): number => {
211
+ if (! root ) {
212
+ return 0 ;
213
+ }
214
+ s += root .val ;
215
+ let ans = cnt .get (s - sum ) ?? 0 ;
216
+ cnt .set (s , (cnt .get (s ) ?? 0 ) + 1 );
217
+ ans += dfs (root .left , s );
218
+ ans += dfs (root .right , s );
219
+ cnt .set (s , (cnt .get (s ) ?? 0 ) - 1 );
220
+ return ans ;
221
+ };
222
+ return dfs (root , 0 );
147
223
}
148
224
```
149
225
@@ -170,38 +246,26 @@ function pathSum(root: TreeNode | null, sum: number): number {
170
246
// }
171
247
use std :: rc :: Rc ;
172
248
use std :: cell :: RefCell ;
173
- use std :: collections :: VecDeque ;
249
+ use std :: collections :: HashMap ;
174
250
impl Solution {
175
- fn dfs (root : & Option <Rc <RefCell <TreeNode >>>, mut sum : i32 ) -> i32 {
176
- let mut res = 0 ;
177
- if root . is_none () {
178
- return res ;
179
- }
180
- let root = root . as_ref (). unwrap (). borrow ();
181
- sum -= root . val;
182
- if sum == 0 {
183
- res += 1 ;
184
- }
185
- res + Self :: dfs (& root . left, sum ) + Self :: dfs (& root . right, sum )
251
+ pub fn path_sum (root : Option <Rc <RefCell <TreeNode >>>, sum : i32 ) -> i32 {
252
+ let mut cnt = HashMap :: new ();
253
+ cnt . insert (0 , 1 );
254
+ return Self :: dfs (root , sum , 0 , & mut cnt );
186
255
}
187
256
188
- pub fn path_sum (root : Option <Rc <RefCell <TreeNode >>>, sum : i32 ) -> i32 {
189
- let mut queue = VecDeque :: new ();
190
- if root . is_some () {
191
- queue . push_back (root );
192
- }
193
- let mut res = 0 ;
194
- while let Some (mut root ) = queue . pop_front () {
195
- res += Self :: dfs (& root , sum );
196
- let mut root = root . as_mut (). unwrap (). borrow_mut ();
197
- if root . left. is_some () {
198
- queue . push_back (root . left. take ());
199
- }
200
- if root . right. is_some () {
201
- queue . push_back (root . right. take ());
202
- }
257
+ fn dfs (root : Option <Rc <RefCell <TreeNode >>>, sum : i32 , s : i32 , cnt : & mut HashMap <i32 , i32 >) -> i32 {
258
+ if let Some (node ) = root {
259
+ let node = node . borrow ();
260
+ let s = s + node . val;
261
+ let mut ans = * cnt . get (& (s - sum )). unwrap_or (& 0 );
262
+ * cnt . entry (s ). or_insert (0 ) += 1 ;
263
+ ans += Self :: dfs (node . left. clone (), sum , s , cnt );
264
+ ans += Self :: dfs (node . right. clone (), sum , s , cnt );
265
+ * cnt . entry (s ). or_insert (0 ) -= 1 ;
266
+ return ans ;
203
267
}
204
- res
268
+ return 0 ;
205
269
}
206
270
}
207
271
```
0 commit comments