zoukankan      html  css  js  c++  java
  • Medium | LeetCode 103 | 剑指 Offer 32

    剑指 Offer 32 - III. 从上到下打印二叉树 III

    请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。

    例如:
    给定二叉树: [3,9,20,null,null,15,7],

        3
       / 
      9  20
        /  
       15   7
    

    返回其层次遍历结果:

    [
      [3],
      [20,9],
      [15,7]
    ]
    

    方法一: 双栈

    由于在遍历时, 当前层的遍历顺序与下一层的遍历顺序相反, 即本层的先放到栈的孩子在遍历下一层时后遍历, 后放到栈的孩子在遍历下一层时先遍历。所以应当使用栈的数据结构。

    使用两个栈实现, 一个栈用于遍历本层的节点, 另一个栈用于存放下一层的节点。

    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if (root == null) {
            return res;
        }
        Deque<TreeNode> stack1 = new ArrayDeque<>();
        Deque<TreeNode> stack2 = new ArrayDeque<>();
        stack1.addLast(root);
        while (!stack1.isEmpty()) {
            List<Integer> res1 = new ArrayList<>();
            while(!stack1.isEmpty()) {
                TreeNode node = stack1.pop();
                res1.add(node.val);
                // 本层是奇数层, 遍历的顺序是从左到右, 所以添加孩子的顺序是先添加左孩子, 再添加右孩子
                if (node.left != null) {
                    stack2.push(node.left);
                }
                if (node.right != null) {
                    stack2.push(node.right);
                }
            }
            res.add(res1);
    
            // 接着遍历偶数层
            List<Integer> res2 = new ArrayList<>();
            while(!stack2.isEmpty()) {
                TreeNode node = stack2.pop();
                res2.add(node.val);
                // 偶数层遍历的顺序是从右到左, 所以应当先添加右孩子, 再添加左孩子
                if (node.right != null) {
                    stack1.push(node.right);
                }
                if (node.left != null) {
                    stack1.push(node.left);
                }
            }
            if (res2.size() > 0) {
                res.add(res2);
            }
        }
        return res;
    }
    

    方法二: 双端队列

    public List<List<Integer>> levelOrder(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        List<List<Integer>> res = new ArrayList<>();
        if(root != null) queue.add(root);
        while(!queue.isEmpty()) {
            LinkedList<Integer> tmp = new LinkedList<>();
            // 入队到queue的过程还是和普通的层次队列一样
            for(int i = queue.size(); i > 0; i--) {
                TreeNode node = queue.poll();
                // 不过出队添加到结果集的过程, 添加到结果集的头部还是尾部就不同了
                if(res.size() % 2 == 0) tmp.addLast(node.val); // 偶数层 -> 队列头部
                else tmp.addFirst(node.val); // 奇数层 -> 队列尾部
                if(node.left != null) queue.add(node.left);
                if(node.right != null) queue.add(node.right);
            }
            res.add(tmp);
        }
        return res;
    }
    

    方法三:奇偶层逻辑分离

    和方法一类似, 不过这里并不需要使用两个队列或者栈, 这里使用一个队列, 不过遍历的顺序是不同的, 和方法一类似, 奇数层的时候, 从从头部出队, 偶数层的时候是从尾部出队, 所以其添加孩子的顺序也不相同。

    public List<List<Integer>> levelOrder(TreeNode root) {
        Deque<TreeNode> deque = new LinkedList<>();
        List<List<Integer>> res = new ArrayList<>();
        if(root != null) deque.add(root);
        while(!deque.isEmpty()) {
            // 打印奇数层
            List<Integer> tmp = new ArrayList<>();
            for(int i = deque.size(); i > 0; i--) {
                // 从左向右打印
                TreeNode node = deque.removeFirst();
                tmp.add(node.val);
                // 先左后右加入下层节点
                if(node.left != null) deque.addLast(node.left);
                if(node.right != null) deque.addLast(node.right);
            }
            res.add(tmp);
            if(deque.isEmpty()) break; // 若为空则提前跳出
            // 打印偶数层
            tmp = new ArrayList<>();
            for(int i = deque.size(); i > 0; i--) {
                // 从右向左打印
                TreeNode node = deque.removeLast();
                tmp.add(node.val);
                // 先右后左加入下层节点
                if(node.right != null) deque.addFirst(node.right);
                if(node.left != null) deque.addFirst(node.left);
            }
            res.add(tmp);
        }
        return res;
    }
    

    方法四: 层次遍历 + 倒序

    这个方法和方法二类似。层次遍历还是常规的层次遍历的方法, 不过在添加到结果集的时候, 可以根据其层数, 选择是否需要将结果颠倒。

    public List<List<Integer>> levelOrder(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        List<List<Integer>> res = new ArrayList<>();
        if(root != null) queue.add(root);
        while(!queue.isEmpty()) {
            List<Integer> tmp = new ArrayList<>();
            for(int i = queue.size(); i > 0; i--) {
                TreeNode node = queue.poll();
                tmp.add(node.val);
                if(node.left != null) queue.add(node.left);
                if(node.right != null) queue.add(node.right);
            }
            if(res.size() % 2 == 1) Collections.reverse(tmp);
            res.add(tmp);
        }
        return res;
    }
    
  • 相关阅读:
    学习数据结构基础
    epoll
    pthread_create
    设置套接字选项
    5中I/O模型
    数据仓库一些整理(列式数据库)
    mysql分区方案的研究
    订单表的分库分表方案设计(大数据)
    从源码角度理清memcache缓存服务
    性能,不是不重要,而是,它没有可维护性重要
  • 原文地址:https://www.cnblogs.com/chenrj97/p/14287496.html
Copyright © 2011-2022 走看看