给定一个二叉树,它的每个结点都存放着一个整数值。
找出路径和等于给定数值的路径总数。
路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。
示例:
一个节点的前缀路径和等于从根节点到该节点的路径上的所有节点值的总和。祖先-子孙节点之间的路径上的和=子孙的前缀路径-祖先的前缀路径。这道题的解决方法就是,判断每个节点,以该节点结尾的路径,有几条总和为sum?
以该节点结尾的路径,且路径方向为从父节点到子节点,那么路径的开端必然是该节点的祖先节点
那么问题就转换为,求每个节点,从其所有祖先节点到该节点的路径中,有几条总和为sum?
我们用一个哈希表来保存当前节点的所有祖先节点的前缀路径信息,键为:前缀路径值a,键值为:前缀路径值为a的所有祖先节点数。
例如当前节点的前缀路径和为suma,当它的某个祖先节点的前缀路径为suma-sum时,该祖先节点到当前节点之间的路径的和即为sum。
然后我们查找哈希表中,前缀路径为:前节点的前缀路径值-sum 的祖先节点数,即为当前节点的路径数。
递归过程:
- 先计算当前节点的前缀路径(用一个变量routesum来保存上一个节点的前缀路径),再找当前节点有多少条总和为sum的前缀路径。
- 更新routesum将当前节点的前缀路径信息放入哈希表中,再计算当前节点的左子树和右子树中有多少条前缀路径。
- 将当前节点的前缀路径信息从哈希表中删除,恢复成之前的状态。再将routesum改成原来的状态(routesum-当前节点值)。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
//一个节点的前缀路径和等于从根节点到该节点的路径上的所有节点值的总和。
//祖先-子孙节点之间的路径上的和=子孙的前缀路径-祖先的前缀路径
//这道题的解决方法就是,判断每个节点,以该节点结尾的路径,有几条总和为sum?
//以该节点结尾的路径,且路径方向为从父节点到子节点,那么路径的开端必然是该节点的祖先节点
//那么问题就转换为,求每个节点,从其所有祖先节点到该节点的路径中,有几条总和为sum?
//我们用一个哈希表来保存当前节点的所有祖先节点的前缀路径信息,键为:前缀路径值a,键值为:前缀路径值为a的所有祖先节点数
//例如当前节点的前缀路径和为suma,当它的某个祖先节点的前缀路径为suma-sum时,该祖先节点到当前节点之间的路径的和即为sum。
//然后我们查找哈希表中,前缀路径为:前节点的前缀路径值-sum 的祖先节点数,即为当前节点的路径数。
class Solution {
int routesum = 0;//当前节点的前缀路径总和
public int findpath(TreeNode root, int sum, Map<Integer,Integer> map)
{
//map中保存的是当前节点的所有祖先节点的前缀路径信息。键,键值: <前缀路径值r,该前缀路径值为r的节点数>
//遍历一棵树,每到一个节点都查找它的所有祖先节点中,有几个祖先节点到该节点的路径和(不包括祖先节点)为sum。
if(root==null)
return 0;
routesum += root.val;
int res = map.getOrDefault(routesum-sum,0);
map.put(routesum,map.getOrDefault(routesum,0)+1);
res += findpath(root.left,sum,map);//查找其左子树上存在几条总和为sum的路径
res += findpath(root.right,sum,map);//查找其右子树上存在几条总和为sum的路径
//当这个节点遍历完左子树和右子树以后,要将其前缀路径信息从map中删除,防止影响到不是他子孙节点的节点
map.put(routesum,map.get(routesum)-1);
routesum-=root.val;
//注意routesum表示的是遍历到的节点的前缀和,所以当这个节点路径和求完以后最后还要减去当前节点的val,以便下一次遍历到的节点计算前缀路径
return res;
}
public int pathSum(TreeNode root, int sum) {
Map<Integer, Integer> map = new HashMap<>();
map.put(0,1);//这里需要注意,这是防止路径上最后一个节点是根节点的情况。如 5-3-null, sum = 8 则 节点3的前缀路径和为8, 8-8=0, 哈希表中有0,值为1, 说明从该字节点到根节点(包括根节点)有一条路径,路径上节点值总和为8
return findpath(root,sum,map);
}
}