43
43
44
44
<!-- 这里可写通用的实现逻辑 -->
45
45
46
- 在遍历的过程中,记录当前路径上的前缀和
46
+ ** 方法一:哈希表 + 前缀和 + 递归**
47
+
48
+ 我们可以运用前缀和的思想,对二叉树进行递归遍历,同时用哈希表 $cnt$ 统计从根节点到当前节点的路径上各个前缀和出现的次数。
49
+
50
+ 我们设计一个递归函数 $dfs(node, s)$,表示当前遍历到的节点为 $node$,从根节点到当前节点的路径上的前缀和为 $s$。函数的返回值是统计以 $node$ 节点及其子树节点作为路径终点且路径和为 $targetSum$ 的路径数目。那么答案就是 $dfs(root, 0)$。
51
+
52
+ 函数 $dfs(node, s)$ 的递归过程如下:
53
+
54
+ - 如果当前节点 $node$ 为空,则返回 $0$。
55
+ - 计算从根节点到当前节点的路径上的前缀和 $s$。
56
+ - 用 $cnt[ s - targetSum] $ 表示以当前节点为路径终点且路径和为 $targetSum$ 的路径数目,其中 $cnt[ s - targetSum] $ 即为 $cnt$ 中前缀和为 $s - targetSum$ 的个数。
57
+ - 将前缀和 $s$ 的计数值加 $1$,即 $cnt[ s] = cnt[ s] + 1$。
58
+ - 递归地遍历当前节点的左右子节点,即调用函数 $dfs(node.left, s)$ 和 $dfs(node.right, s)$,并将它们的返回值相加。
59
+ - 在返回值计算完成以后,需要将当前节点的前缀和 $s$ 的计数值减 $1$,即执行 $cnt[ s] = cnt[ s] - 1$。
60
+ - 最后返回答案。
61
+
62
+ 时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是二叉树的节点个数。
47
63
48
64
<!-- tabs:start -->
49
65
59
75
# self.left = left
60
76
# self.right = right
61
77
class Solution :
62
- def pathSum (self , root : TreeNode, targetSum : int ) -> int :
63
- preSum = defaultdict(int )
64
- preSum[0 ] = 1
65
-
66
- def dfs (node : TreeNode, cur : int ) -> int :
67
- if not node:
78
+ def pathSum (self , root : Optional[TreeNode], targetSum : int ) -> int :
79
+ def dfs (node , s ):
80
+ if node is None :
68
81
return 0
69
-
70
- cur += node.val
71
- ret = preSum[cur - targetSum]
72
-
73
- preSum[cur] += 1
74
- ret += dfs(node.left, cur)
75
- ret += dfs(node.right, cur)
76
- preSum[cur] -= 1
77
-
78
- return ret
79
-
82
+ s += node.val
83
+ ans = cnt[s - targetSum]
84
+ cnt[s] += 1
85
+ ans += dfs(node.left, s)
86
+ ans += dfs(node.right, s)
87
+ cnt[s] -= 1
88
+ return ans
89
+
90
+ cnt = Counter({0 : 1 })
80
91
return dfs(root, 0 )
81
92
```
82
93
@@ -101,68 +112,30 @@ class Solution:
101
112
* }
102
113
*/
103
114
class Solution {
104
-
105
- private final Map< Integer , Integer > preSum = new HashMap<> () ;
115
+ private Map< Long , Integer > cnt = new HashMap<> ();
116
+ private int targetSum ;
106
117
107
118
public int pathSum (TreeNode root , int targetSum ) {
108
- preSum. put(0 , 1 );
109
- return dfs(root, 0 , targetSum);
119
+ cnt. put(0L , 1 );
120
+ this . targetSum = targetSum;
121
+ return dfs(root, 0 );
110
122
}
111
123
112
- private int dfs (TreeNode node , int cur , int targetSum ) {
124
+ private int dfs (TreeNode node , long s ) {
113
125
if (node == null ) {
114
126
return 0 ;
115
127
}
116
-
117
- cur += node. val;
118
- int ret = preSum. getOrDefault(cur - targetSum, 0 );
119
-
120
- preSum. merge(cur, 1 , Integer :: sum);
121
- ret += dfs(node. left, cur, targetSum);
122
- ret += dfs(node. right, cur, targetSum);
123
- preSum. merge(cur, - 1 , Integer :: sum);
124
-
125
- return ret;
128
+ s += node. val;
129
+ int ans = cnt. getOrDefault(s - targetSum, 0 );
130
+ cnt. merge(s, 1 , Integer :: sum);
131
+ ans += dfs(node. left, s);
132
+ ans += dfs(node. right, s);
133
+ cnt. merge(s, - 1 , Integer :: sum);
134
+ return ans;
126
135
}
127
136
}
128
137
```
129
138
130
- ### ** Go**
131
-
132
- ``` go
133
- /* *
134
- * Definition for a binary tree node.
135
- * type TreeNode struct {
136
- * Val int
137
- * Left *TreeNode
138
- * Right *TreeNode
139
- * }
140
- */
141
- func pathSum (root *TreeNode , targetSum int ) int {
142
- preSum := make (map [int ]int )
143
- preSum[0 ] = 1
144
-
145
- var dfs func (*TreeNode, int ) int
146
- dfs = func (node *TreeNode, cur int ) int {
147
- if node == nil {
148
- return 0
149
- }
150
-
151
- cur += node.Val
152
- ret := preSum[cur-targetSum]
153
-
154
- preSum[cur]++
155
- ret += dfs (node.Left , cur)
156
- ret += dfs (node.Right , cur)
157
- preSum[cur]--
158
-
159
- return ret
160
- }
161
-
162
- return dfs (root, 0 )
163
- }
164
- ```
165
-
166
139
### ** C++**
167
140
168
141
``` cpp
@@ -180,30 +153,51 @@ func pathSum(root *TreeNode, targetSum int) int {
180
153
class Solution {
181
154
public:
182
155
int pathSum(TreeNode* root, int targetSum) {
183
- unordered_map<int, int> preSum;
184
- preSum[ 0] = 1;
185
-
186
- function<int(TreeNode*, int)> dfs = [&](TreeNode* node, int cur) {
187
- if (node == nullptr) {
188
- return 0;
189
- }
190
-
191
- cur += node->val;
192
- int ret = preSum[cur - targetSum];
193
-
194
- ++preSum[cur];
195
- ret += dfs(node->left, cur);
196
- ret += dfs(node->right, cur);
197
- --preSum[cur];
198
-
199
- return ret;
156
+ unordered_map<long, int> cnt;
157
+ cnt[ 0] = 1;
158
+ function<int(TreeNode* , long)> dfs = [ &] (TreeNode* node, long s) -> int {
159
+ if (!node) return 0;
160
+ s += node->val;
161
+ int ans = cnt[ s - targetSum] ;
162
+ ++cnt[ s] ;
163
+ ans += dfs(node->left, s) + dfs(node->right, s);
164
+ --cnt[ s] ;
165
+ return ans;
200
166
};
201
-
202
167
return dfs(root, 0);
203
168
}
204
169
};
205
170
```
206
171
172
+ ### **Go**
173
+
174
+ ```go
175
+ /**
176
+ * Definition for a binary tree node.
177
+ * type TreeNode struct {
178
+ * Val int
179
+ * Left *TreeNode
180
+ * Right *TreeNode
181
+ * }
182
+ */
183
+ func pathSum(root *TreeNode, targetSum int) int {
184
+ cnt := map[int]int{0: 1}
185
+ var dfs func(*TreeNode, int) int
186
+ dfs = func(node *TreeNode, s int) int {
187
+ if node == nil {
188
+ return 0
189
+ }
190
+ s += node.Val
191
+ ans := cnt[s-targetSum]
192
+ cnt[s]++
193
+ ans += dfs(node.Left, s) + dfs(node.Right, s)
194
+ cnt[s]--
195
+ return ans
196
+ }
197
+ return dfs(root, 0)
198
+ }
199
+ ```
200
+
207
201
### ** ...**
208
202
209
203
```
0 commit comments