(一)路径总和
题目(Easy):112. 路径总和
题目描述:
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22,
5
/
4 8
/ /
11 13 4
/
7 2 1
返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。
解题思路:
本题是一个典型的二叉树深度遍历问题,最直接的方法是使用递归,历整棵树:如果当前节点不是叶子,对它的所有孩子节点,递归调用 hasPathSum 函数,其中 sum 值减去当前节点的权值;如果当前节点是叶子,检查 sum 值是否为 0,也就是是否找到了给定的目标和。
当然,除了递归之外,还可以使用栈的方式进行迭代,两种方法的实现可以参见代码。
代码实现:
//方法一:递归
class Solution {
public boolean hasPathSum(TreeNode root, int sum) {
if(root==null)
return false;
sum-=root.val;
if(root.left==null && root.right==null){ //叶结点
if(sum==0)
return true;
}
return hasPathSum(root.left,sum) || hasPathSum(root.right,sum);
}
}
//方法二:迭代
import java.util.*;
public class Solution {
public boolean hasPathSum(TreeNode root, int sum) {
if(root==null)
return false;
Stack<TreeNode> node_stack=new Stack<>();
Stack<Integer> sum_stack=new Stack<>();
node_stack.push(root);
sum_stack.push(sum-root.val);
while(!node_stack.isEmpty()){
TreeNode node=node_stack.pop();
int curSum=sum_stack.pop();
if(node.left==null && node.right==null && curSum==0)
return true;
if(node.right!=null){
node_stack.push(node.right);
sum_stack.push(curSum-node.right.val);
}
if(node.left!=null){
node_stack.push(node.left);
sum_stack.push(curSum-node.left.val);
}
}
return false;
}
}
(二)路径总和II
题目(Medium):113. 路径总和 II
题目描述:
给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22,
5
/
4 8
/ /
11 13 4
/ /
7 2 5 1
返回:
[
[5,4,11,2],
[5,8,4,5]
]
解题思路:【剑指Offer】 24、二叉树中和为某一值的路径
本题实质上就是深度优先搜索。使用前序遍历的方式对整棵树进行遍历,当访问到某一个结点时,将该结点添加到路径上,并且累加该结点的值。当访问到的结点是叶结点时,如果路径中的结点值之和正好等于输入的整数,则说明是一条符合要求的路径。如果当前结点不是叶结点,则继续访问它的子结点。
当找到一条符合要求的路径之后,需要回溯进一步查找别的路径,因此,这实际上仍然是一个递归的过程,特别注意在函数返回之前要删掉当前结点,从而才可以正确的回溯。
代码实现:
class Solution {
List<List<Integer>> res=new ArrayList<>();
public List<List<Integer>> pathSum(TreeNode root, int sum) {
if(root==null)
return res;
List<Integer> temp=new ArrayList<>();
findPath(root,sum,temp);
return res;
}
public void findPath(TreeNode root,int target,List<Integer> temp){
temp.add(root.val);
if(root.left==null && root.right==null){
if(target==root.val){
List<Integer> list=new ArrayList<>();
list.addAll(temp);
res.add(list);
}
}else{
if(root.left!=null)
findPath(root.left,target-root.val,temp);
if(root.right!=null)
findPath(root.right,target-root.val,temp);
}
if(temp.size()!=0)
temp.remove(temp.size()-1);
}
}
(三)路径总和III
题目(Easy):437. 路径总和 III
题目描述:
给定一个二叉树,它的每个结点都存放着一个整数值。找出路径和等于给定数值的路径总数。路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。
示例:
root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8
10
/
5 -3
/
3 2 11
/
3 -2 1
返回 3。和等于 8 的路径有:
1. 5 -> 3
2. 5 -> 2 -> 1
3. -3 -> 11
解题思路:
如果问题是找出以根结点为起点,任意结点结束,并且路径上和为sum的路径个数,那么此问题只需要直接前序遍历就可以递归解决,而现在是任意结点都可以作为起点,那么只需要多考虑每一个起点即可,同样是递归的应用。
代码实现:
class Solution {
public int pathSum(TreeNode root, int sum) {
if(root==null)
return 0;
return dfs(root,sum) + pathSum(root.left,sum) + pathSum(root.right,sum);
}
public int dfs(TreeNode root,int sum){ //以root为根,到任意一点的路径和为sum
if(root==null)
return 0;
int res=0;
if(root.val==sum)
res+=1;
res+= dfs(root.left,sum-root.val); //左子树递归
res+= dfs(root.right,sum-root.val); //右子树递归
return res;
}
}
(四)二叉树中的最大路径和
题目(hard):124. 二叉树中的最大路径和
题目描述:
给定一个非空二叉树,返回其最大路径和。本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列。该路径至少包含一个节点,且不一定经过根节点。
示例:
输入: [1,2,3]
1
/
2 3
输出: 6
输入: [-10,9,20,null,null,15,7]
-10
/
9 20
/
15 7
输出: 42
解题思路:
- 初始化 max_sum 为最小可能的整数并调用函数 max_gain(node = root)。
- 实现 max_gain(node) 检查是继续旧路径还是开始新路径:
- 边界情况:如果节点为空,那么最大权值是 0 。
- 对该节点的所有孩子递归调用 max_gain,计算从左右子树的最大权值:left_gain = max(max_gain(node.left), 0) 和 right_gain = max(max_gain(node.right), 0)。
- 检查是维护旧路径还是创建新路径。创建新路径的权值是:price_newpath = node.val + left_gain + right_gain,当新路径更好的时候更新 max_sum。
- 对于递归返回的到当前节点的一条最大路径,计算结果为:node.val + max(left_gain, right_gain)。
代码实现:
class Solution {
int max=Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
if(root==null)
return 0;
dfs(root);
return max;
}
public int dfs(TreeNode root){ //路径经过root的路径和
if(root==null)
return 0;
//计算左分支最大值
int leftMax=Math.max(dfs(root.left),0);
//计算右分支最大值
int rightMax=Math.max(dfs(root.right),0);
max=Math.max(max,root.val+leftMax+rightMax);
//返回单路分支
return root.val+Math.max(leftMax,rightMax); //关键,计算单边分支的路径
}
}
总结:
本文总结了四道关于二叉树路径和的相关问题,其中最主要的是二叉树前序深度遍历和递归算法的应用,要注意回溯思想及相关算法思想的应用。