算法通关村第六关——树层序遍历白银挑战笔记

该部分内容主要针对树层序遍历这个高频考点展开,细致深入的分析树层序遍历的模板,以及应用模板解决变式问题的思路,仔细总结复盘就可以掌握树层序遍历部分的出题方向,你也能成为出算法题的大牛,给自己出题,给自己解答!(独孤求败)

1.树层次遍历

树的层次遍历,掌握模板即可,模板里面最重要的是什么?答:队列

关键点在于掌握队列和树节点入队出队的逻辑逻辑为队头元素出队并保存出队元素的元素值,该元素的左右孩子节点依次入队,如果左右孩子为空则不入队,直到队列为空层序遍历结束。

厘清思路,直接上代码!

    public static List<Integer> simpleLevelOrder(TreeNode root) {
        if(root == null){
            return new ArrayList<Integer>();
        }
        Queue<TreeNode> queue = new LinkedList<>();
        ArrayList<Integer> res = new ArrayList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            TreeNode curNode = queue.poll();
            res.add(curNode.val);
            if(curNode.left != null){
                queue.add(curNode.left);
            }
            if(curNode.right != null){
                queue.add(curNode.right);
            }
        }
        return res;
    }

2.二叉树从上至下逐层遍历

该问题是树层序遍历的第一类变式问题,该问题主要考察是否能在层序遍历中找到每层的树节点。这个问题的关键点是在于怎样标记树每层末尾节点可以使用一个变量size来记录本层到底有多少个节点,当size==0时,将本层的节点放到一个数组中进行保存,层次遍历的整体逻辑是逐层遍历!直接上代码,更易于理解!

    public static List<List<Integer>> mylLevel102Order(TreeNode root) {
        if(root == null){
            return new ArrayList<List<Integer>>();
        }
        Queue<TreeNode> queue = new LinkedList<>();
        ArrayList<List<Integer>> res = new ArrayList<>();
        queue.offer(root);
        ArrayList<Integer> ansLevel = new ArrayList<>();
        int size = 0;
        while(!queue.isEmpty()){
            size = queue.size();
            ArrayList<Integer> tmp = new ArrayList<>();
            //遍历第每层
            for(int i = 0; i < size; i++){
                TreeNode curNode = queue.poll();
                tmp.add(curNode.val);
                if(curNode.left!=null){
                    queue.add(curNode.left);
                }
                if(curNode.right!=null){
                    queue.add(curNode.right);
                }
            }
            res.add(tmp);
        }
        return res;
    }

3.二叉树从下至上层序遍历

该问题是针对问题2的变式,在问题2中我们已经能够逐层获得树节点信息,而问题三考察的点在于如何把每一层的树节点信息逆序存储起来。我猜你已经想到了!“逆向过程”可以使用头插法。

没错两种方法都可以,这里我们采用头插法进行!直接上代码!

    public static List<List<Integer>> myLevelOrderBottom(TreeNode root) {
        if(root == null){
            return new LinkedList<List<Integer>>();
        }
        LinkedList<List<Integer>> res = new LinkedList<>();
        LinkedList<TreeNode> queue = new LinkedList<>();
        int size = 0;
        queue.add(root);
        while(!queue.isEmpty()){
            size = queue.size();
            ArrayList<Integer> tmp = new ArrayList<>();
            for (int i = 0; i < size; i++) {
                TreeNode t = queue.remove();
                tmp.add(t.val);
                if(t.left != null){
                    queue.add(t.left);
                }
                if(t.right != null){
                    queue.add(t.right);
                }
            }
            res.addFirst(tmp);
        }
        return res;
    }

4.二叉树的锯齿形层序遍历

什么是锯齿形层序遍历?就是蛇形层序遍历。那我懂了,偶数层正向输出节点,奇数层反向输出节点。什么数据结构既能顺序输出,又能逆序输出?答:对端队列

还是套用层序遍历模板,采用双端队列存储每层元素,当偶数层正常入队,奇数层从头部入队,即可完成锯齿形层序遍历。厘清逻辑,直接上代码!

    public static List<List<Integer>> myZigzagLevelOrder(TreeNode root) {
        ArrayList<List<Integer>> res = new ArrayList<>();
        if(root == null){
            return res;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        boolean isEven = true;//是否为偶数层
        int size = 0;
        while(!queue.isEmpty()){
            size = queue.size();
            Deque<Integer> levelList = new LinkedList<>();
            for (int i = 0; i < size; i++) {
                TreeNode t = queue.poll();
                if(isEven){
                    levelList.offerLast(t.val);
                }
                if(!isEven){
                    levelList.offerFirst(t.val);
                }
                if(t.left != null){
                    queue.offer(t.left);
                }
                if(t.right != null){
                    queue.offer(t.right);
                }
            }
            res.add(new ArrayList<Integer>(levelList));
            isEven = !isEven;
        }
        return res;

5.N叉树层序遍历

N叉树层序遍历有什么难度嘛?Paper tiger!只不过把左右孩子入队变成孩子节点全部入队了倘若我能将孩子节点“正向存储(从左至右)”和“逆向存储(从右至左)”那么依然可以变幻出诸如,N叉树锯齿形层序遍历的问题,可以多思考一下,大有裨益!厘清思路,直接上代码!

注意,我们此时没有使用size来标记本层末尾树节点,相反使用一个辅助队列可以记录本层树节点,这也是一类方法,应该值得注意!!!!

    public static List<List<Integer>> nLevelOrder(NTreeNode root) {
        List<List<Integer>> value = new ArrayList<>();
        Deque<NTreeNode> q = new ArrayDeque<>();
        if (root != null)
            q.addLast(root);
        while (!q.isEmpty()) {
            Deque<NTreeNode> next = new ArrayDeque<>();
            List<Integer> nd = new ArrayList<>();
            while (!q.isEmpty()) {
                NTreeNode cur = q.pollFirst();
                nd.add(cur.val);
                for (NTreeNode chd : cur.children) {
                    if (chd != null)
                        next.add(chd);
                }
            }
            q = next;
            value.add(nd);
        }
        return value;
    }

6.树每层元素的问题

我们知道树每层元素存储到一个数组中,数组头部存储该层最左侧树节点,数组尾部存储该层最右侧树节点,依然可以使用一个辅助变量max或min记录本层树节点的最大值,亦可求解平均值。因此,该类问题的变式问题分成,树每层最大(小)值树每层平均值树左(右)视图三类问题!

树每层最大值

经过上面的分析,可以直接上代码!

    public static List<Integer> myLargestValues(TreeNode root) {
        ArrayList<Integer> res = new ArrayList<>();
        if(root == null){
            return res;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            Queue<TreeNode> next = new LinkedList<>();//下一层节点
            int max = Integer.MIN_VALUE;
            while(!queue.isEmpty()){
                TreeNode t = queue.poll();
                max = Math.max(t.val, max);
                if(t.left!=null){
                    next.offer(t.left);
                }
                if(t.right!=null){
                    next.offer(t.right);
                }
            }
            res.add(max);
            queue = next;
        }
        return res;
    }

树每层平均值

经过上面的分析,可以直接上代码!

    public static List<Double> myAverageOfLevels(TreeNode root) {
        ArrayList<Double> res = new ArrayList<>();
        if(root == null){
            return res;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int size = 0;
        while(!queue.isEmpty()){
            int sum = 0;
            size = queue.size();
            for (int i = 0; i < size; i++) {
                TreeNode t = queue.poll();
                sum += t.val;
                if(t.left!=null){
                    queue.offer(t.left);
                }
                if(t.right!=null){
                    queue.offer(t.right);
                }
            }
            res.add(1.0 * sum / size);
        }
        return res;
    }

树右视图

经过上面的分析,可以直接上代码!

    public static List<Integer> myRightSideView(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if (root == null) {
            return res;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int size = 0;
        while (!queue.isEmpty()) {
            size = queue.size();
            int rightNodeVal = 0;
            for (int i = 0; i < size; i++) {
                TreeNode t = queue.poll();
                if(t.left != null) queue.offer(t.left);
                if(t.right != null) queue.offer(t.right);
                if(i == size - 1) rightNodeVal = t.val;
            }
            res.add(rightNodeVal);
        }
        return res;
    }

OK,《算法通关村第六关——树层序遍历白银挑战笔记》结束,喜欢的朋友三联加关注!关注鱼市带给你不一样的算法小感悟!(幻听)

再次,感谢鱼骨头教官的学习路线!鱼皮的宣传!小y的陪伴!ok,拜拜,第七关第一幕见!

很难坚持下来,可坚持下来了,也就不觉得难!加油!今天化身杰迷,去看了张杰长沙演唱会!虽然在场外,让我想起了五年前在杭州,依旧是场外听张杰唱歌的场景!期待下一次演唱会,我又会是什么样子!于2023年7月29日!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值