DAY18|513.找树左下角的值 、112. 路径总和、113.路径总和ii、106.从中序与后序遍历序列构造二叉树(区间的重要性)、105.从前序与中序遍历序列构造二叉树

文章介绍了如何使用递归和迭代方法解决二叉树的相关问题,包括找树左下角的值、路径总和以及从遍历序列构造二叉树。递归法在某些问题上可能更直观,而迭代法则通常更简洁。对于路径总和问题,回溯过程是关键。同时,提供了从遍历序列构造二叉树的算法,强调理解切割子树的逻辑。
摘要由CSDN通过智能技术生成

513.找树左下角的值
本地递归偏难,反而迭代简单属于模板题, 两种方法掌握一下
左侧节点不一定是左孩子
可以使用前序遍历(当然中序,后序都可以)优先遍历左侧 左侧没有就去找右侧了
在这里插入图片描述

class Solution {
    public int Deep=-1;
    public int res=0;//用来记录每一层的第一个值 即最左侧的值
    public int findBottomLeftValue(TreeNode root) {
        res=root.val;
        findLeftValue(root,0);//更改res的值 所以返回void就可以
        return res;
    }
    public void findLeftValue(TreeNode root,int deep){
        if(root==null) return;
        if(root.left==null&&root.right==null){
            if(deep>Deep){
                res=root.val;
                Deep=deep; //不可以Deep++,因为有递归不是每一层都能按顺序++,但是deep是按照顺序++
            }
        }
        if (root.left != null) findLeftValue(root.left,deep+1);//不可以用deep++!!!!!!!!!!
        if (root.right != null) findLeftValue(root.right,deep+1);
    }
}

迭代法

class Solution {
    public int findBottomLeftValue(TreeNode root) {
        Queue<TreeNode> queue=new LinkedList<>();
        queue.offer(root);
        int res=root.val;
        while(!queue.isEmpty()){//一次while循环是一层
            int size=queue.size();//记录一下每轮这一层的数量
            for(int i=0;i<size;i++){//记录当前层的最左侧值,并按照这一层的数量往队列里放入下一层的值(for循环)
                TreeNode poll=queue.poll();
                if (i == 0) {
                    res = poll.val;
                }
                if(poll.left!=null){
                    queue.offer(poll.left);
                }
                if(poll.right!=null){
                    queue.offer(poll.right);
                }
            }
        }
        return res;
    }
}
  1. 路径总和
    本题 又一次设计要回溯的过程,而且回溯的过程隐藏的还挺深,建议先看视频来理解

没有中的处理逻辑的话 前中后序都可以
这里用中序
在这里插入图片描述

class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if(root==null) return false;
        targetSum-=root.val;
        if(root.left==null&&root.right==null){
            return targetSum==0;//返回最后目标值是否减为0
            
        }
        if(root.left!=null){
            // return hasPathSum(root.left, targetSum);
           boolean left = hasPathSum(root.left, targetSum);
            if (left) {      // 已经找到
                return true;
            }
        }
        if(root.right!=null){
            // return hasPathSum(root.right, targetSum);//不对!!!!没找到也返回了就不会继续找了
             boolean right = hasPathSum(root.right, targetSum);
            if (right) {      // 找到了才返回,没找到不返回
                return true;
            }
        }
        return false;//以上都没找到才会运行
    }
}
  1. 路径总和,和 113. 路径总和ii 一起做了。 优先掌握递归法。

113.路径总和ii
在这里插入图片描述

class Solution {
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        List<List<Integer>> res=new ArrayList<>();
        if(root==null) return res;
        List<Integer> paths=new ArrayList<>();
        findPath(root,res,paths,targetSum);//找到path放到res中
        return res;
    }
    public void findPath(TreeNode root, List<List<Integer>> res, List<Integer> paths, int targetSum){
        if(root==null) return;
        paths.add(root.val);
        targetSum-=root.val;
        if(root.right==null&&root.left==null){
            if(targetSum==0){
                res.add(new ArrayList<>(paths));//必须这么做!!(看图片)
            }
            return;
        }

        if(root.left!=null){
            findPath(root.left,res,paths,targetSum);
            paths.remove(paths.size() - 1); // 回溯
        }
            
        if(root.right!=null){
            findPath(root.right,res,paths,targetSum);
            paths.remove(paths.size() - 1); // 回溯
        }
    }
}

106.从中序与后序遍历序列构造二叉树
(别看代码随想录的答案)
本题算是比较难的二叉树题目了,大家先看视频来理解。
每次从中序遍历中找到中间节点去切割前序遍历
在这里插入图片描述
在这里插入图片描述

class Solution {

    int post_idx;
    int[] postorder;
    int[] inorder;
    Map<Integer, Integer> map = new HashMap<Integer, Integer>();

    public TreeNode buildTree(int[] inorder, int[] postorder) {
        //
        this.postorder = postorder;
        this.inorder = inorder;
        // 从后序遍历的最后一个元素开始
        post_idx = postorder.length - 1;

        // 建立(元素,下标)键值对的哈希表 元素是key 下标是value
        int idx = 0;
        for (Integer val : inorder) {
            map.put(val, idx++);
        }
        
        return helper(0, inorder.length - 1);
    }

        public TreeNode helper(int in_left, int in_right) {
        // 如果这里没有节点构造二叉树了,就结束
        if (in_left > in_right) {
            return null;
        }

        // 选择 post_idx 位置的元素作为当前子树根节点
        int root_val = postorder[post_idx];
        TreeNode root = new TreeNode(root_val);

        // 根据 root 所在位置将前序分成左右两棵子树
        int in_root_index = map.get(root_val);

        // 下标减一
        post_idx--;

        // 构造右子树
        root.right = helper(in_root_index + 1, in_right);
        // 构造左子树
        root.left = helper(in_left, in_root_index - 1);
        
        return root;
    }
}

106.从中序与后序遍历序列构造二叉树,105.从前序与中序遍历序列构造二叉树 一起做,思路一样的

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

class Solution {

    int pre_idx;
    int[] preorder;
    int[] inorder;
    Map<Integer, Integer> map = new HashMap<Integer, Integer>();

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        //
        this.preorder = preorder;
        this.inorder = inorder;
        // 从前序遍历的第一个元素开始
        pre_idx = 0;

        // 建立中序(元素,下标)键值对的哈希表 元素是key 下标是value 用元素找下表
        int idx = 0;
        for (Integer val : inorder) {
            map.put(val, idx++);
        }
        
        return helper(0, inorder.length - 1);
    }

        public TreeNode helper(int in_left, int in_right) {
        // 如果这里没有节点构造二叉树了,就结束
        if (in_left > in_right) {
            return null;
        }

        // 选择 前序遍历中的pre_idx 位置的元素作为当前子树根节点
        int root_val = preorder[pre_idx];//
        TreeNode root = new TreeNode(root_val);

        // 根据 root_val 所在位置将前序分成左右两棵子树
        int in_root_index = map.get(root_val);

        // 下标++
        pre_idx++;
        
        // 构造左子树
        root.left = helper(in_left, in_root_index - 1);
        // 构造右子树
        root.right = helper(in_root_index + 1, in_right);
        
        
        return root;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值