Skip to content

Commit b2e987f

Browse files
committed
feat: update solutions to lcof2 problem: No.050
fix doocs#899
1 parent f325b4c commit b2e987f

File tree

5 files changed

+126
-154
lines changed

5 files changed

+126
-154
lines changed

lcof2/剑指 Offer II 050. 向下的路径节点之和/README.md

Lines changed: 81 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,23 @@
4545

4646
<!-- 这里可写通用的实现逻辑 -->
4747

48-
在遍历的过程中,记录当前路径上的前缀和
48+
**方法一:哈希表 + 前缀和 + 递归**
49+
50+
我们可以运用前缀和的思想,对二叉树进行递归遍历,同时用哈希表 $cnt$ 统计从根节点到当前节点的路径上各个前缀和出现的次数。
51+
52+
我们设计一个递归函数 $dfs(node, s)$,表示当前遍历到的节点为 $node$,从根节点到当前节点的路径上的前缀和为 $s$。函数的返回值是统计以 $node$ 节点及其子树节点作为路径终点且路径和为 $targetSum$ 的路径数目。那么答案就是 $dfs(root, 0)$。
53+
54+
函数 $dfs(node, s)$ 的递归过程如下:
55+
56+
- 如果当前节点 $node$ 为空,则返回 $0$。
57+
- 计算从根节点到当前节点的路径上的前缀和 $s$。
58+
- 用 $cnt[s - targetSum]$ 表示以当前节点为路径终点且路径和为 $targetSum$ 的路径数目,其中 $cnt[s - targetSum]$ 即为 $cnt$ 中前缀和为 $s - targetSum$ 的个数。
59+
- 将前缀和 $s$ 的计数值加 $1$,即 $cnt[s] = cnt[s] + 1$。
60+
- 递归地遍历当前节点的左右子节点,即调用函数 $dfs(node.left, s)$ 和 $dfs(node.right, s)$,并将它们的返回值相加。
61+
- 在返回值计算完成以后,需要将当前节点的前缀和 $s$ 的计数值减 $1$,即执行 $cnt[s] = cnt[s] - 1$。
62+
- 最后返回答案。
63+
64+
时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是二叉树的节点个数。
4965

5066
<!-- tabs:start -->
5167

@@ -61,24 +77,19 @@
6177
# self.left = left
6278
# self.right = right
6379
class Solution:
64-
def pathSum(self, root: TreeNode, targetSum: int) -> int:
65-
preSum = defaultdict(int)
66-
preSum[0] = 1
67-
68-
def dfs(node: TreeNode, cur: int) -> int:
69-
if not node:
80+
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> int:
81+
def dfs(node, s):
82+
if node is None:
7083
return 0
71-
72-
cur += node.val
73-
ret = preSum[cur - targetSum]
74-
75-
preSum[cur] += 1
76-
ret += dfs(node.left, cur)
77-
ret += dfs(node.right, cur)
78-
preSum[cur] -= 1
79-
80-
return ret
81-
84+
s += node.val
85+
ans = cnt[s - targetSum]
86+
cnt[s] += 1
87+
ans += dfs(node.left, s)
88+
ans += dfs(node.right, s)
89+
cnt[s] -= 1
90+
return ans
91+
92+
cnt = Counter({0: 1})
8293
return dfs(root, 0)
8394
```
8495

@@ -103,68 +114,30 @@ class Solution:
103114
* }
104115
*/
105116
class Solution {
106-
107-
private final Map<Integer, Integer> preSum = new HashMap<>();
117+
private Map<Long, Integer> cnt = new HashMap<>();
118+
private int targetSum;
108119

109120
public int pathSum(TreeNode root, int targetSum) {
110-
preSum.put(0, 1);
111-
return dfs(root, 0, targetSum);
121+
cnt.put(0L, 1);
122+
this.targetSum = targetSum;
123+
return dfs(root, 0);
112124
}
113125

114-
private int dfs(TreeNode node, int cur, int targetSum) {
126+
private int dfs(TreeNode node, long s) {
115127
if (node == null) {
116128
return 0;
117129
}
118-
119-
cur += node.val;
120-
int ret = preSum.getOrDefault(cur - targetSum, 0);
121-
122-
preSum.merge(cur, 1, Integer::sum);
123-
ret += dfs(node.left, cur, targetSum);
124-
ret += dfs(node.right, cur, targetSum);
125-
preSum.merge(cur, -1, Integer::sum);
126-
127-
return ret;
130+
s += node.val;
131+
int ans = cnt.getOrDefault(s - targetSum, 0);
132+
cnt.merge(s, 1, Integer::sum);
133+
ans += dfs(node.left, s);
134+
ans += dfs(node.right, s);
135+
cnt.merge(s, -1, Integer::sum);
136+
return ans;
128137
}
129138
}
130139
```
131140

132-
### **Go**
133-
134-
```go
135-
/**
136-
* Definition for a binary tree node.
137-
* type TreeNode struct {
138-
* Val int
139-
* Left *TreeNode
140-
* Right *TreeNode
141-
* }
142-
*/
143-
func pathSum(root *TreeNode, targetSum int) int {
144-
preSum := make(map[int]int)
145-
preSum[0] = 1
146-
147-
var dfs func(*TreeNode, int) int
148-
dfs = func(node *TreeNode, cur int) int {
149-
if node == nil {
150-
return 0
151-
}
152-
153-
cur += node.Val
154-
ret := preSum[cur-targetSum]
155-
156-
preSum[cur]++
157-
ret += dfs(node.Left, cur)
158-
ret += dfs(node.Right, cur)
159-
preSum[cur]--
160-
161-
return ret
162-
}
163-
164-
return dfs(root, 0)
165-
}
166-
```
167-
168141
### **C++**
169142

170143
```cpp
@@ -182,30 +155,51 @@ func pathSum(root *TreeNode, targetSum int) int {
182155
class Solution {
183156
public:
184157
int pathSum(TreeNode* root, int targetSum) {
185-
unordered_map<int, int> preSum;
186-
preSum[0] = 1;
187-
188-
function<int(TreeNode*, int)> dfs = [&](TreeNode* node, int cur) {
189-
if (node == nullptr) {
190-
return 0;
191-
}
192-
193-
cur += node->val;
194-
int ret = preSum[cur - targetSum];
195-
196-
++preSum[cur];
197-
ret += dfs(node->left, cur);
198-
ret += dfs(node->right, cur);
199-
--preSum[cur];
200-
201-
return ret;
158+
unordered_map<long, int> cnt;
159+
cnt[0] = 1;
160+
function<int(TreeNode*, long)> dfs = [&](TreeNode* node, long s) -> int {
161+
if (!node) return 0;
162+
s += node->val;
163+
int ans = cnt[s - targetSum];
164+
++cnt[s];
165+
ans += dfs(node->left, s) + dfs(node->right, s);
166+
--cnt[s];
167+
return ans;
202168
};
203-
204169
return dfs(root, 0);
205170
}
206171
};
207172
```
208173
174+
### **Go**
175+
176+
```go
177+
/**
178+
* Definition for a binary tree node.
179+
* type TreeNode struct {
180+
* Val int
181+
* Left *TreeNode
182+
* Right *TreeNode
183+
* }
184+
*/
185+
func pathSum(root *TreeNode, targetSum int) int {
186+
cnt := map[int]int{0: 1}
187+
var dfs func(*TreeNode, int) int
188+
dfs = func(node *TreeNode, s int) int {
189+
if node == nil {
190+
return 0
191+
}
192+
s += node.Val
193+
ans := cnt[s-targetSum]
194+
cnt[s]++
195+
ans += dfs(node.Left, s) + dfs(node.Right, s)
196+
cnt[s]--
197+
return ans
198+
}
199+
return dfs(root, 0)
200+
}
201+
```
202+
209203
### **...**
210204

211205
```

lcof2/剑指 Offer II 050. 向下的路径节点之和/Solution.cpp

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,17 @@
1212
class Solution {
1313
public:
1414
int pathSum(TreeNode* root, int targetSum) {
15-
unordered_map<int, int> preSum;
16-
preSum[0] = 1;
17-
18-
function<int(TreeNode*, int)> dfs = [&](TreeNode* node, int cur) {
19-
if (node == nullptr) {
20-
return 0;
21-
}
22-
23-
cur += node->val;
24-
int ret = preSum[cur - targetSum];
25-
26-
++preSum[cur];
27-
ret += dfs(node->left, cur);
28-
ret += dfs(node->right, cur);
29-
--preSum[cur];
30-
31-
return ret;
15+
unordered_map<long, int> cnt;
16+
cnt[0] = 1;
17+
function<int(TreeNode*, long)> dfs = [&](TreeNode* node, long s) -> int {
18+
if (!node) return 0;
19+
s += node->val;
20+
int ans = cnt[s - targetSum];
21+
++cnt[s];
22+
ans += dfs(node->left, s) + dfs(node->right, s);
23+
--cnt[s];
24+
return ans;
3225
};
33-
3426
return dfs(root, 0);
3527
}
36-
};
28+
};

lcof2/剑指 Offer II 050. 向下的路径节点之和/Solution.go

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,18 @@
77
* }
88
*/
99
func pathSum(root *TreeNode, targetSum int) int {
10-
preSum := make(map[int]int)
11-
preSum[0] = 1
12-
10+
cnt := map[int]int{0: 1}
1311
var dfs func(*TreeNode, int) int
14-
dfs = func(node *TreeNode, cur int) int {
12+
dfs = func(node *TreeNode, s int) int {
1513
if node == nil {
1614
return 0
1715
}
18-
19-
cur += node.Val
20-
ret := preSum[cur-targetSum]
21-
22-
preSum[cur]++
23-
ret += dfs(node.Left, cur)
24-
ret += dfs(node.Right, cur)
25-
preSum[cur]--
26-
27-
return ret
16+
s += node.Val
17+
ans := cnt[s-targetSum]
18+
cnt[s]++
19+
ans += dfs(node.Left, s) + dfs(node.Right, s)
20+
cnt[s]--
21+
return ans
2822
}
29-
3023
return dfs(root, 0)
31-
}
24+
}

lcof2/剑指 Offer II 050. 向下的路径节点之和/Solution.java

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,25 @@
1414
* }
1515
*/
1616
class Solution {
17-
18-
private final Map<Integer, Integer> preSum = new HashMap<>();
17+
private Map<Long, Integer> cnt = new HashMap<>();
18+
private int targetSum;
1919

2020
public int pathSum(TreeNode root, int targetSum) {
21-
preSum.put(0, 1);
22-
return dfs(root, 0, targetSum);
21+
cnt.put(0L, 1);
22+
this.targetSum = targetSum;
23+
return dfs(root, 0);
2324
}
2425

25-
private int dfs(TreeNode node, int cur, int targetSum) {
26+
private int dfs(TreeNode node, long s) {
2627
if (node == null) {
2728
return 0;
2829
}
29-
30-
cur += node.val;
31-
int ret = preSum.getOrDefault(cur - targetSum, 0);
32-
33-
preSum.merge(cur, 1, Integer::sum);
34-
ret += dfs(node.left, cur, targetSum);
35-
ret += dfs(node.right, cur, targetSum);
36-
preSum.merge(cur, -1, Integer::sum);
37-
38-
return ret;
30+
s += node.val;
31+
int ans = cnt.getOrDefault(s - targetSum, 0);
32+
cnt.merge(s, 1, Integer::sum);
33+
ans += dfs(node.left, s);
34+
ans += dfs(node.right, s);
35+
cnt.merge(s, -1, Integer::sum);
36+
return ans;
3937
}
40-
}
38+
}

lcof2/剑指 Offer II 050. 向下的路径节点之和/Solution.py

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,17 @@
55
# self.left = left
66
# self.right = right
77
class Solution:
8-
def pathSum(self, root: TreeNode, targetSum: int) -> int:
9-
preSum = defaultdict(int)
10-
preSum[0] = 1
11-
12-
def dfs(node: TreeNode, cur: int) -> int:
13-
if not node:
8+
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> int:
9+
def dfs(node, s):
10+
if node is None:
1411
return 0
12+
s += node.val
13+
ans = cnt[s - targetSum]
14+
cnt[s] += 1
15+
ans += dfs(node.left, s)
16+
ans += dfs(node.right, s)
17+
cnt[s] -= 1
18+
return ans
1519

16-
cur += node.val
17-
ret = preSum[cur - targetSum]
18-
19-
preSum[cur] += 1
20-
ret += dfs(node.left, cur)
21-
ret += dfs(node.right, cur)
22-
preSum[cur] -= 1
23-
24-
return ret
25-
20+
cnt = Counter({0: 1})
2621
return dfs(root, 0)

0 commit comments

Comments
 (0)