题目描述
给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
算法思路
方法1:bfs进行穷举。
方法2:前缀和结合哈希表
1 前缀和的概念:前缀和就是在根节点到当前节点的路径中,包含当前节点值在内的所有节点val的和。
2 前缀和的应用:两个节点的前缀和差值 = 这两个节点的路径和
3 哈希表的作用:
Map.getOrDefault(key,默认值);
Map中会存储一一对应的key和value。
如果 在Map中存在key,则返回key所对应的的value。
如果 在Map中不存在key,则返回默认值。
在本题中,key表示前缀和,value表示前缀和为该值的节点的个数
4 为什么要回溯:
举个例子,下图中有两个值为2的节点(A, B)。
0
/
A:2 B:2
/ \
4 5 6
/ \
7 8 9
当我们遍历到最右方的节点6时,对于它来说,此时的前缀和为2的节点只该有B, 因为从A向下到不了节点6(A并不是节点6的祖先节点)。
如果我们不做状态恢复,当遍历右子树时,左子树中A的信息仍会保留在map中,那此时节点6就会认为A, B都是可追溯到的节点,从而产生错误。
状态恢复代码的作用就是: 在遍历完一个节点的所有子节点后,将其从map中除去。
示例代码1
class Solution {
int res, target;
public int pathSum(TreeNode root, int targetSum) {
target = targetSum;
dfs1(root);
return res;
}
public void dfs1(TreeNode root) {
if (root == null) return;
dfs2(root, root.val);
dfs1(root.left);
dfs1(root.right);
}
public void dfs2(TreeNode root, int val) {
if (val == target)
res++;
if (root.left != null)
dfs2(root.left, val + root.left.val);
if (root.right != null)
dfs2(root.right, val + root.right.val);
}
}
示例代码2
class Solution {
Map<Integer,Integer> mem = new HashMap<Integer,Integer>();//保存前缀树
int target;
public int pathSum(TreeNode root, int targetSum) {
target = targetSum;
//前缀树为0的个数至少是一个,key是前缀和,value是个数
mem.put(0,1);
return dfs(root,0);
}
public int dfs(TreeNode root,int curSum){
if(root == null) return 0;
curSum += root.val;//得到当前前缀树的值
int res = 0;
//如果有curSum-target的节点存在,返回对应的个数,否则返回0
res = mem.getOrDefault(curSum-target,0);//得到我们想要前缀树的个数,想要前缀树值就是当前前缀树值减去目标值
mem.put(curSum,mem.getOrDefault(curSum,0)+1);//将当前前缀树的值保存
int left = dfs(root.left,curSum);//遍历左边
int right = dfs(root.right,curSum);//遍历右边
mem.put(curSum,mem.get(curSum)-1);//防止左边前缀树影响右边前缀树,左边前缀树可能有个为6,右边正好想要一个前缀树为6的,这样子就出错了
return res+left+right;//结果是当前节点前缀树的个数加上左边满足的个数加右边满足的个数
}
}