【LeetCode】二叉树路径和及其相关问题(4)

(一)路径总和

题目(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);  //关键,计算单边分支的路径
    }
}

总结:

  本文总结了四道关于二叉树路径和的相关问题,其中最主要的是二叉树前序深度遍历和递归算法的应用,要注意回溯思想及相关算法思想的应用。

猜你喜欢

转载自www.cnblogs.com/gzshan/p/12629278.html
今日推荐