每日打卡:二叉树的锯齿形层序遍历

131 阅读2分钟

这是我参与2022首次更文挑战的第17天,活动详情查看:2022首次更文挑战

给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

输入:root = [3,9,20,null,null,15,7] 输出: [[3],[20,9],[15,7]]

原题链接

首先,我先声明这和昨天的可不是一道题属于他的一个变种,如果做过昨天的那道题,今天的题应该很容易就像出来

没看过的同学大家可以先参考一下,二叉树的层序遍历

我们分析一下我们这两道题具体是有什么区别呢?

一个是层序遍历,一个是锯齿形层序,我们特殊的地方就是我们我们每一层都要换一个方向,首先,大家不要进入一个误区,就是让我们的遍历顺序按照我们输出的方式去遍历,那我们做起来就会很麻烦,我看到这道题第一个想法就是,我们利用上一道题的遍历顺序,我们在装入list集合的时候我们呢反着装不就可以了?那怎么把一个集合反转呢?我一个想到的就是一种数据结构——栈,先入栈,在出栈,存入集合,完美!

public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        List<List<Integer>> result =new LinkedList<List<Integer>>();
        if(root==null){
            return result;
        }
        Queue<TreeNode> nodeQueue = new LinkedList<TreeNode>();
        nodeQueue.add(root);
        //控制反转
        boolean q = true;
        while (!nodeQueue.isEmpty()){
            List<Integer> list = new ArrayList<Integer>();
            Stack<Integer> stack = new Stack<Integer>();
            int size = nodeQueue.size();
            for (int i = 0; i < size; i++){
                TreeNode node = nodeQueue.poll();
                //需要反转的时候使数据入栈
                if(!q){
                    stack.push(node.val);
                }else {
                    list.add(node.val);
                }
                if(node.left!=null){
                    nodeQueue.offer(node.left);
                }
                if (node.right != null) {
                    nodeQueue.offer(node.right);
                }
            }
            //相同条件判断,使数据出栈,存入集合
            if(!q){
                int s = stack.size();
                for (int i = 0; i < s; i++){
                    list.add(stack.pop());
                }
            }
            result.add(list);
            q=!q;
        }
        return result;
    }

但是,之后我去看了一下官方文档,去学习一下,唉,这一看不得了,我发现原来有一种数据结构叫做双向队列,他和队列的区别就是它两端都可以进出,虽然之前学过,可是忘没了,如果我们使用双向队列来做,代码就更加简单了

public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        List<List<Integer>> result =new LinkedList<List<Integer>>();
        if(root==null){
            return result;
        }
        Queue<TreeNode> nodeQueue = new LinkedList<TreeNode>();
        nodeQueue.add(root);
        boolean q = true;
        while (!nodeQueue.isEmpty()){
            Deque<Integer> deque = new LinkedList<Integer>();
            int size = nodeQueue.size();
            for (int i = 0; i < size; i++){
                TreeNode node = nodeQueue.poll();
                //根据判断符号来控制从前后入队
                if(!q){
                    deque.addFirst(node.val);
                }else {
                    deque.addLast(node.val);
                }
                if(node.left!=null){
                    nodeQueue.offer(node.left);
                }
                if (node.right != null) {
                    nodeQueue.offer(node.right);
                }
            }
            
            result.add(new LinkedList<Integer>(deque));
            q=!q;
        }
        return result;
    }

两种解法,执行用时和内存消耗都差不多,对于我使用栈的方式将他倒转,我们会多开辟一块空间用来存储我们的栈,如果使用双向队列就会节省一部分空间,还是建议使用双向队列。

最后,对于为什么我们在把我们双线队列填入我们result的时候需要new LinkedList?

因为我们的队列不是集合我们的类型不同不能直接装入,虽然都是LinkedList实现,这涉及到泛型问题,大家可以搜一搜,解释的都比我好。