一、题目描述
You are given a binary tree in which each node contains an integer value.
Find the number of paths that sum to a given value.
The path does not need to start or end at the root or a leaf,
but it must go downwards (traveling only from parent nodes to child nodes).
The tree has no more than 1,000 nodes and the values are in the range -1,000,000 to 1,000,000.
Example:
root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8
10
/ \
5 -3
/ \ \
3 2 11
/ \ \
3 -2 1
Return 3. The paths that sum to 8 are:
1. 5 -> 3
2. 5 -> 2 -> 1
3. -3 -> 11
二、题解
方法一:递归
* 这题第一次做的时候让我感到最疑惑的是:
- Q1:为什么要用多层递归。
A1:后来才发现路径的开头可以不是根节点,结束也可以不是叶子节点。所以我们要将每一个结点作为开头地去枚举每一个结点。
其他和 I,II 还是不变。
int cnt;
public int pathSum(TreeNode root, int sum) {
if (root == null)
return 0;
dfs(root, sum);
pathSum(root.left, sum);
pathSum(root.right, sum);
return cnt;
}
void dfs(TreeNode root, int re) {
if (root == null) {
return;
}
if (re == root.val) {
cnt++;
}
dfs(root.left, re-root.val);
dfs(root.right, re-root.val);
}
复杂度分析
- 时间复杂度: ,
- 空间复杂度: ,
方法二:累加区间
对于 path 中的每一个结点,我们都从该结点往回枚举,查看是否有路径匹配。
- Q1:能不能找到一条路径之后,直接终止循环?
A1:反例是 root = [0,1,1],sum = 1,答案是 4。 - Q2:为什么从后往前遍历列表?
A2:因为这样保证末尾结点与之前的结点的可组合性。- 比如:A1 的反例,1 算一种,[1, 0] 算一种,如果从前往后遍历则会少一种。
int cnt = 0;
int sum = 0;
List<Integer> path = null;
public int pathSum(TreeNode root, int target) {
sum = target;
path = new ArrayList<>();
dfs(root);
return cnt;
}
private void dfs(TreeNode root) {
if (root == null) {
return;
}
path.add(root.val);
int t = 0;
for (int i = path.size()-1; i >= 0; i++) {
t += path.get(i);
if (t == sum) {
cnt++;
//break; 不能提前break [1],[1,0]
}
}
dfs(root.left);
dfs(root.right);
path.remove(path.size()-1);
}
复杂度分析
- 时间复杂度: ,
- 空间复杂度: ,
方法二:前缀和
如果 map 中存在 cur-sum,证明我们从结点 cur-sum 开始走到当前结点的路径是一条合法路径。例如:我们知道 sum = 11 的路径。我们走到叶子结点 3,路径总和为 21,21 - 11 = 10,map 中可能会存在 10 的前缀和。
一句话:如果有前缀和和 cur - sum,而当前的和又为 cur,一定存在一条差为 cur - (cur - sum) 的路径。
10
/
5
/
3
/
3
int cnt = 0;
int sum = 0;
int cur = 0;
Map<Integer, Integer> map = null;
public int pathSum(TreeNode root, int target) {
map = new HashMap<>();
map.put(0, 1);
sum = target;
dfs(root);
return cnt;
}
private void dfs(TreeNode root) {
if (root == null) {
return;
}
cur += root.val;
cnt += map.getOrDefault(cur - sum, 0);
map.put(cur, map.getOrDefault(cur, 0) + 1);
dfs(root.left);
dfs(root.right);
// 回溯
cur -= root.val;
map.put(cur, map.get(cur) - 1);
}
复杂度分析
- 时间复杂度: ,
- 空间复杂度: ,