One, Title Description
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
Second, the problem solution
Method One: recursive
* This title first time when I am most puzzled is:
- Q1: Why use a multi-layer recursion.
A1: later discovered at the beginning of the path may not be the root node, may not be the end of the leaf nodes. So we want each node as a beginning to go enumerate each node.
Other and I, II or unchanged.
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);
}
Complexity Analysis
- time complexity: ,
- Space complexity: ,
Method two: accumulating section
For each node in the path, we are back from the node enumeration to see if there is a path match.
- Q1: After I can find a path, direct termination cycle?
A1: counter-example is the root = [0,1,1], sum = 1, the answer is 4. - Q2: Why iterate forward from the list?
A2: Because this combination can guarantee the end of the junction with the previous node.- For example: A1 counterexamples, considered a 1, [1, 0] considered a, if at least one front to back will be traversed.
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);
}
Complexity Analysis
- time complexity: ,
- Space complexity: ,
Method Two: prefix and
If the map there is cur-sum, prove that we began to come from the node cur-sum current node path is a legitimate path. For example: We know that sum = path 11. We went leaf node 3, the sum of the path 21, 21 --11 = 10, there may be a prefix 10 and the map.
Bottom line: If you have a prefix and and cur - sum, but also for current and cur, there must be a difference cur - (cur - sum) path.
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);
}
Complexity Analysis
- time complexity: ,
- Space complexity: ,