路径总和
题目链接:https://leetcode-cn.com/problems/path-sum-iii
一、问题描述
给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
示例 1:
输入:root = [10,5,-3,3,2,null,11,3,-2,null,1], targetSum = 8
输出:3
解释:和等于 8 的路径有 3 条,如图所示。
示例 2:
输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:3
二、解题思路
暴力解法就是遍历每条路径,并且求和,如果求和得出目标值就做记录。
如果对暴力法进行分析,其实遍历求和的过程中做了很多重复计算,参考他人题解后采用前缀和方法,对每个节点的遍历都进行记录,可以免除重复计算。
从根节点开始,向下遍历(深度优先),遍历到下层节点时,计算一个前缀和curSum,然后拿这个前缀和减去目标值tar,如果这个结果能在保存的map中找到映射,说明在当前节点上方的某个节点开始,到当前节点就是我们要找的一条路径。可以设当前节点为A,它的祖先节点为B,那么从根节点到A的路径就可以表示成root—>B—>A,此时B的前趋和就是从根节点到B的路径总和,A的前趋和减去B的前趋和就是B节点到A的值,如果这个值等于tar,那么B到A就是要找的一条路径,还有一点需要注意,因为不限制开始结束节点,所以一条路径上可能有多条符合要求的子路径。
三、算法
可以采用深度优先算法,而且进行回溯,在退出当前路径时,要从map中移除当前路径前趋和的键值对,这样在其他路径使用map时不会产生重复计算这类问题
1 class Solution { 2 public int pathSum(TreeNode root, int targetSum) { 3 Map<Integer, Integer> prefixSumCount = new HashMap<>(); 4 prefixSumCount.put(0,1); 5 int res = DFS(root,prefixSumCount,0,targetSum); 6 return res; 7 } 8 9 public int DFS(TreeNode node,Map<Integer, Integer> prefixSumCount,int curSum,int targetSum){ 10 if( node == null){ 11 return 0; 12 } 13 int res = 0; 14 curSum += node.val; 15 //getordefault函数,如果curSum-targetSum的值存在,就返回这个值,如果不存在就返回0 16 res += prefixSumCount.getOrDefault(curSum - targetSum, 0); 17 //把当前路径和存入map 18 prefixSumCount.put(curSum, prefixSumCount.getOrDefault(curSum, 0) + 1); 19 20 //向后两颗子树遍历 21 res += DFS(node.left,prefixSumCount,curSum,targetSum); 22 res += DFS(node.right,prefixSumCount,curSum,targetSum); 23 24 //函数返回后删除该路径在map中的映射用于 25 prefixSumCount.put(curSum,prefixSumCount.get(curSum)-1); 26 return res; 27 } 28 }
对于map<K,V>;K表示某个前趋和,V表示前趋和是K的节点数,此时就可处理一条路径上多条符合要求的子路径问题,例如root—>A—>B—>C,如果B的前缀和于A相等,那么对应C来说就有两条子路径分别是AC和BC,这种情况的原因是AB之间存在负数节点于正节点抵消,导致AB的路径和为0。
原文:https://www.cnblogs.com/zyq79434/p/15145157.html