**
剑指offer 二叉树中和为某一值的路径
**
题目描述
输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)
提到树,首先就应该想起用递归操作。
这道题的路径要求是从root到leaf,根据题目,递归的终止条件就是node.left == null && node.right == null && node.val == target
public class Solution {
public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
if(root == null) return res;
helper(root , target , new ArrayList<Integer>() , res);
return res;
}
public void helper(TreeNode node , int target , ArrayList<Integer> list , ArrayList<ArrayList<Integer>> res) {
list.add(node.val);
if(node.left == null && node.right == null && node.val == target) {
res.add(new ArrayList<>(list));
}
if(node.left != null) helper(node.left , target-node.val , list , res);
if(node.right != null) helper(node.right , target-node.val , list , res );
list.remove(list.size()-1);
}
}
Leetcode 112. Path Sum
Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.
同类型题,只是没有要求把结果返回,只是判断,所以更加简单
class Solution {
public boolean hasPathSum(TreeNode node, int target) {
if(node == null) return false;
if(node.left == null && node.right == null && node.val == target) return true;
return hasPathSum(node.left , target-node.val) || hasPathSum(node.right , target-node.val);
}
}
Leetcode 113.Path Sum II
与剑指offer是同一题
Leetcode 437. Path Sum III
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.
这道题对路径的start和end没有要求,也就是说路径start和end不必是树的root和leaf,所以,我们需要对树的每一个节点都做判断,以当前节点为start的路径,拥有多少条路径和为sum的路径,所有这些路径加起来,就是结果。
class Solution {
public int pathSum(TreeNode root, int sum) {
if(root == null) return 0;
int res = 0;
res += helper(root , sum);
res += pathSum(root.left , sum) + pathSum(root.right , sum);
return res;
}
//以node为start,返回有多少条路径和为target
public int helper(TreeNode node , int target ) {
if(node == null) return 0;
int num = 0;
if(node.val == target) num += 1;
num += helper(node.left , target-node.val );
num += helper(node.right , target-node.val);
return num;
}
}
在discuss中找到的该题的另一个解决方案,比较难懂
discuss
class Solution {
public int pathSum(TreeNode root, int sum) {
HashMap<Integer, Integer> preSum = new HashMap();
preSum.put(0,1);
return helper(root, 0, sum, preSum);
}
public int helper(TreeNode root, int currSum, int target, HashMap<Integer, Integer> preSum) {
if (root == null) {
return 0;
}
currSum += root.val;
int res = preSum.getOrDefault(currSum - target, 0);
preSum.put(currSum, preSum.getOrDefault(currSum, 0) + 1);
res += helper(root.left, currSum, target, preSum) + helper(root.right, currSum, target, preSum);
preSum.put(currSum, preSum.get(currSum) - 1);
return res;
}
}
解释:
因此,这个想法类似于两个和,使用HASMAP来存储(关键字:前缀和,值:有多少种方法得到这个前缀和),并且每当到达一个节点,我们检查前缀和目标是否存在于HASMAP中,如果有,我们将前缀和目标的方式添加到REST中。
例如:在一个路径中,我们有1,2,-1,-1,2,那么前缀和将是:1,3,2,1,3,假设我们要找到的目标和是2,那么我们将有{2},{1,2,-1},{2,-1,-1,2}和{2}方法。
1、前缀存储递归中从根到当前节点的和
2、在到达当前节点之前,映射存储<prefix sum,frequency>对。我们可以想象从根到当前节点的路径。从路径中间到当前节点的任何节点的总和=从根到当前节点的总和和中间节点的前缀和之间的差值。
3、我们正在寻找一些连续的节点,这些节点的总和为给定的目标值,这意味着在2中讨论的差异。应该等于目标值。此外,我们需要知道有多少差异等于目标值。
4、地图来了。映射存储当前节点路径中所有可能和的频率。如果在地图中存在当前和和目标值之间的差异,则在路径的中间必须存在一个节点,使得从该节点到当前节点,总和等于目标值。
5、注意,中间可能有多个节点满足4中讨论的内容。地图上的频率是用来帮助解决这个问题的。
6、因此,在每次递归中,映射都会存储我们计算到目标的范围总数所需的所有信息。请注意,每个范围从中间节点开始,由当前节点结束。
7、为了得到路径总数,我们将树中每个节点结束的有效路径数相加。
8、每个递归返回以当前节点为root的子树中有效路径的总数。这个总数可以分为三部分:
-子树中以当前节点的左子节点为root的有效路径总数
-子树中以当前节点的右子节点为root的有效路径总数
-以当前节点为end的有效路径数