day18|513.找树左下角的值、112. 路径总和、113. 路径总和ii、106.从中序与后序遍历序列构造二叉树,105.从前序与中序遍历序列构造二叉树

513. 找树左下角的值

题目:

给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。
假设二叉树中至少有一个节点。

在这里插入图片描述
思路:
找树的左下角的值
这句话翻译过来就是找树最下层的第一个值
这样的话其实迭代的法是最简单的解法

迭代解法

  • 迭代就的使用队列,一层一层的入队,
  • 根节点入队;
  • 队列迭代,队列非空
  • 记录队列的size(树层的size),
  • 第一个出队的就是结果,后续回会覆盖
  • 把后续的左右节点再入队

代码实现

    public int maxLeftVal(TreeNode root) {
        int res = 0;
        //队列
        Queue<TreeNode> queue = new LinkedList<>();
        //根节点入队列
        queue.offer(root);
        while (!queue.isEmpty()) {
            //一层一层迭代,size 代表每一层的节点个数
            int size = queue.size(); //这里取的是记录值,不能是实时值,很重要!!!
            for (int i = 0; i < size; i++) {
                //遍历这一层的节点
                TreeNode node = queue.poll();
                if(i==0){
                    //第一个就是最左边的,后续层迭代会覆盖
                    res = node.value;
                }
                if(node.left!=null){
                    //下层子节点加入队列
                    queue.offer(node.left);
                }
                if(node.right!=null){
                    //下层右节点加入队列
                    queue.offer(node.left);
                }
            }
        }
        return res;
    }

递归解法
其实就是层一层深入,找到左边最深层即为结果

  • 遍历顺序可以是前序,也可以是中序,也可以是后续,保证左在前就行,
  • 定义一个标志位,-1
  • 深度每加一层,更新一下最大深度
  • 返回深度的value,因为左边比右边先入栈,所以如果左边会覆盖右边的值

代码实现

public class MaxLeftVal {

    int value ;
    int Deep = -1;
    public int maxLeftVal_2(TreeNode root) {
        value = root.value;
        findLeftValue(root,0);
        return value;
    }

    private void findLeftValue(TreeNode root, int deep) {
        if(root==null) return;
        if(root.left == null && root.right==null){
            //叶子节点
            if(deep > Deep){
                //返回左节点的值(因为左边先入栈,所有左边深的话会更新深度)
              value = root.value;
                //更新深度
              Deep = deep;
            }
        }
        if(root.left!=null) findLeftValue(root.left,deep+1);
        if(root.right!=null) findLeftValue(root.right,deep+1);

    }


}

112. 路径总和

题目:

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。
叶子节点 是指没有子节点的节点。
在这里插入图片描述
思路:

  • 看到目标值相到了什么 ,是不是就是判断目标值-其中一个值,另一个值是不是等于这个差值啊
  • num1+num2=target;
  • target-num1=num2;
  • 二叉树 :1->2;1->3; 目标值是 3
  • 1+2 =3 符合 ;
  • 此题的最小问题出来了:
   if(node.left ==null && node.right==null){
      return node.val == target;
    }
  boolean leftHashPathSum = hashPathSum(node.left,target-node.val);
  boolean rightHashPathSum = hashPathSum(node.right,target-node.val);
  return leftHashPathSum || rightHashPathSum; (有一个路径呢符合就行)

代码实现

  public boolean hasPathSum(TreeNode node, int target) {
        if(node == null) return false;
        if(node.left == null && node.right == null){
            return node.value == target;
        }
        boolean leftHashPathSum = hasPathSum(node.left,target-node.value);
        boolean rightHashPathSum = hasPathSum(node.right,target-node.value);
        return  leftHashPathSum || rightHashPathSum;
    }

113. 路径总和 II

题目

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。

在这里插入图片描述
思路

  • 借助之前求两数之和、路径之和、回溯的思路
  • 要找到所有的根节点到叶子结点的路径之和,所以要用到回溯

代码实现

   public List<List<Integer>> pathSum(TreeNode root, int targetSum){
        List<List<Integer>> res = new ArrayList<>();
        if(root == null) return res;
        
        List<Integer> path =new LinkedList<>();
        getPathSum(root,path,res,targetSum);
        return res;
    }

    private void getPathSum(TreeNode root,
                            List<Integer> path,
                            List<List<Integer>> res,
                            int targetSum) {
        path.add(root.value);
        if(root.left == null && root.right == null ){
            if(root.value == targetSum){
                res.add(new ArrayList<>(path));
            }
            return;
        }
        if(root.left!= null){
            getPathSum(root.left,path,res,targetSum-root.value);
            path.remove(path.size()-1);
        }
        if(root.right!= null){
            getPathSum(root.right,path,res,targetSum-root.value);
            path.remove(path.size()-1);
        }
    }

106. 从中序与后序遍历序列构造二叉树

题目

给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
在这里插入图片描述

思路

  • 关键点在于利用中序、后续的特点
  • 后续的最后一位是中间节点
  • 确定中间节点之后是不是在通过同样的方法获取到左子树和右子树呢?
    • 首先根后续数组的最后一个节点获取根节点
    • 并且得到中序数组的切割位置 rootIndex,同时可以知道坐子树的长度 leftLen =(rootIndex - inBegin)
    • 根据中间切割位:rootIndex 和 左子树的长度 leftLen,切割左中序、切割左后序 ,这样就有了左子树
    • 切割右中序,右后序,这样就有了右子树

代码实现

  class Solution {
    
    private Map<Integer,Integer> inorderMap;

    public TreeNode buildTree(int[] inorder, int[] postorder) {
          inorderMap = new HashMap<>();
          for(int i=0;i<inorder.length;i++){
              inorderMap.put(inorder[i],i);
          }
          return findNode(inorder,0,inorder.length,postorder,0,postorder.length);

    }

    private TreeNode findNode(int[] inorder,int inBegin, int inEnd, int[] postorder,int postBegin,int postEnd){
        if(inBegin >= inEnd || postBegin >= postEnd){
            return null;
        }
        int rootIndex =  inorderMap.get(postorder[postEnd-1]);
        TreeNode root =new TreeNode(inorder[rootIndex]);
        int leftLen = rootIndex - inBegin;
        root.left = findNode(inorder,inBegin,rootIndex,postorder,postBegin,postBegin+leftLen);
        root.right = findNode(inorder,rootIndex+1,inEnd,postorder,postBegin+leftLen,postEnd-1);
        return root;
    }
}

105. 从前序与中序遍历序列构造二叉树

题目

给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

在这里插入图片描述

思路与 “从中序与后序遍历序列构造二叉树” 是一致

代码实现

  class Solution {

    //存储中序数组的元素和所以位置
    private Map<Integer,Integer> inOrderMap;

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        inOrderMap =new HashMap<>();
        for(int i=0; i< inorder.length;i++){
          inOrderMap.put(inorder[i],i);
        }
        TreeNode node = findNode(preorder,0,preorder.length,inorder,0,inorder.length);
        return node;
    }

    private TreeNode findNode(int[] preorder,int preBegin, int preEnd,int[] inorder,int inBegin,int inEnd){
        if(preBegin >= preEnd || inBegin >= inEnd){
            return null;
        }
        //根据前序数组的首元素确定中间节点
        int rootIndex = inOrderMap.get(preorder[preBegin]);
        //中间节点
        TreeNode root = new TreeNode (preorder [preBegin]);
        //根据中序数组确定左子树的长度,其实是为了确定左前序的数组结束位置
        int leftLen = rootIndex - inBegin;
        //左节点,根据左前序,左中序获取
        root.left = findNode(preorder,preBegin+1,preBegin+1+leftLen,inorder,inBegin,inBegin+leftLen);
        //右节点,根据右前序、右中序确定
        root.right = findNode(preorder,preBegin+1+leftLen,preEnd,inorder,rootIndex+1,inEnd);
        return root;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值