问题描述
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 to leaf
,而该题是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).
解法1 :
一颗以root为根的树,其路径和等于sum的路径个数可由以下三部分 组成:
路径以root 开头 路径不以root开头
左子树中等于sum的路径个数 右子树中等于sum的路径个数 所以以上是两个递归,而递归的终止条件又有所不同,递归终止条件为空结点结束 。 时间复杂度: T(N) = 2T(N/2) + O(N)
,根据Master
公式,可知 复杂度为O(NlogN)
解法2 :
该解法真是将DFS吃透了。 首先有一个引题,那便是给定一个数组,有正有负有0,如何找到子数组和为target的所有子数组个数? 利用HashMap ,将从0索引到任一个位置的数组和都加入map中,假设此时数组中已经有了 0~0, 0~1…0~i -1范围的子数组和,那么当遍历到 i位置时,此时 0~i的数组和为curSum,检查map中是否存在curSum - target 值,若有,则说明从数组的某一位置到i位置,这形成的子数组和便是target。 为了不遗漏从0索引开始的位置 ,初始时,将<0, -1>放入map中。key为路径和,value为索引。 这样便是O(N) 下找到了所有子数组和为sum的子数组。回到该题,如果我们将数中的一条路径看做数组的话,那么便是同样的情况,为了统计路径个个数,key存从根节点到某中间节点的路径和,value存出现该路径和的次数。 可是这是一颗二叉树,存在多条从根到 叶子节点的路径,那么只能通过 DFS + 回溯 来控制map,保证map中始终维持的是一条从根到叶子节点的路径相关路径和信息 。具体见实现。 时间复杂度:O(N)
经验教训
两种思路都很巧妙,尤其第二种,简直巧夺天工。多看多理解 dfs+ 回溯
代码实现
public int pathSum(TreeNode root, int sum ) {
if (root == null ) {
return 0 ;
}
return pathSum(root.left, sum ) + pathSum(root.right, sum ) + findPath(root, sum );
}
public int findPath(TreeNode root, int sum ) {
if (root == null ) {
return 0 ;
}
int res = 0 ;
if (sum == root.val) {
res += 1 ;
}
res += findPath(root.left, sum - root.val);
res += findPath(root.right, sum - root.val);
return res;
}
public int pathSum(TreeNode root, int sum ) {
HashMap<Integer, Integer> sumMap = new HashMap<>();
sumMap.put(0 ,1 );
return dfs(root, 0 , sum , sumMap);
}
public int dfs(TreeNode root, int preSum, int sum , HashMap<Integer, Integer> sumMap) {
if (root == null ) {
return 0 ;
}
int curSum = preSum + root.val;
int res = 0 ;
res += sumMap.getOrDefault(curSum - sum , 0 );
sumMap.put(curSum, sumMap.getOrDefault(curSum, 0 ) + 1 );
res += dfs(root.left, curSum, sum , sumMap) + dfs(root.right, curSum, sum , sumMap);
sumMap.put(curSum, sumMap.get(curSum) - 1 );
return res;
}