【JZ-32-III】从上到下打印二叉树(树、BFS、队列)

目录

题目

【JZ-32-III】从上到下打印二叉树(树、BFS、队列)
在【JZ-32-II】的基础上,要求打印每一层的方向交替变化,即,奇数层正序打印,偶数层倒序打印。
参考

方法一-层序遍历+双端队列

算法思路

算法流程:
1. 特例处理: 根节点 r o o t root root 为空时,直接返回空列表
2. 初始化: 结果列表 r e s res res 和 包含根节点的双端队列 d e q u e deque deque
3. BFS循环,当队列 d e q u e deque deque 为空时跳出循环:

  1. 新建一个临时列表 t m p tmp tmp,用来存储当前这层的打印结果
  2. 当前层打印循环(循环次数为当前层节点数,即 d e q u e deque deque 长度):
    队首元素出队,记为 n o d e node node;
    打印该元素,若为奇数层,则将 n o d e . v a l node.val node.val 添加到列表 t m p tmp tmp 尾部;若为偶数层,则将 n o d e . v a l node.val node.val 添加到列表 t m p tmp tmp 头部
    若 n o d e node node 的左右子节点不为空,则将子节点加入队列 d e q u e deque deque
  3. 将当前层打印结果 t m p tmp tmp 转化为 list 并添加到结果列表 r e s res res

4. 返回值: 结果列表 r e s res res

关于如何判断奇数层还是偶数层
res.size()为偶数时,当前层为奇数层; res.size()为奇数时,当前层为偶数层

具体代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        Deque<TreeNode> deque = new LinkedList<>();//双端队列初始化
        List<List<Integer>> res = new ArrayList<>();//结果列表初始化
        if(root != null)deque.offerLast(root);//根节点尾部入队
        while(!deque.isEmpty()){
            LinkedList<Integer> tmp = new LinkedList<>();//临时列表,存储当前层的打印结果
            for(int i = deque.size(); i > 0; i--){
                TreeNode node = deque.pollFirst();//队首元素出队
                if(res.size() % 2 == 0)tmp.offerLast(node.val);//奇数层,列表尾部添加
                else tmp.offerFirst(node.val);//偶数层,列表头部添加
                //子节点入队
                if(node.left != null)deque.offerLast(node.left);
                if(node.right != null)deque.offerLast(node.right);
            }
            res.add(tmp);//当前层打印结果添加到结果列表
        }
        return res;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),n 为二叉树节点总数。因为 BFS 需要循环 n 次,双端队列的队首和队尾添加操作、删除操作的时间复杂度均为 O ( 1 ) O(1) O(1)
  • 空间复杂度: O ( n ) O(n) O(n),因为在最坏情况下,即,树为平衡二叉树时,最多会有 n / 2 n/2 n/2 个节点同时在队列 d e q u e deque deque 中,占用了 O ( n ) O(n) O(n) 大小的额外空间。

方法二-奇偶层逻辑分离

算法思路

在方法一的基础上,将奇偶层逻辑拆分,消除冗余的判断(方法一中需要判断每一个节点所在层的奇偶性)

算法流程(只有BFS循环部分与方法一不同)

BFS循环,当队列 d e q u e deque deque 为空时跳出循环:

  1. 打印奇数层:从左向右打印,先左后右加入下层节点
  2. 打印偶数层:从右向左打印,先右后左加入下层节点

具体代码

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        Deque<TreeNode> deque = new LinkedList<>();//双端队列初始化
        List<List<Integer>> res = new ArrayList<>();//结果列表初始化
        if(root != null)deque.offerLast(root);//根节点尾部入队
        while(!deque.isEmpty()){
            //打印奇数层
            LinkedList<Integer> tmp = new LinkedList<>();//临时列表,存储当前层的打印结果
            for(int i = deque.size(); i > 0; i--){
                //从左向右打印
                TreeNode node = deque.pollFirst();//队首元素出队
                tmp.offerLast(node.val);
                //先左后右加入下层节点
                if(node.left != null)deque.offerLast(node.left);
                if(node.right != null)deque.offerLast(node.right);
            }
            res.add(tmp);//当前层打印结果添加到结果列表
            if(deque.isEmpty())break;//若队列为空提前跳出
            //打印偶数层
            tmp = new LinkedList<>();
            for(int i = deque.size(); i > 0; i--){
                //从右向左打印
                TreeNode node = deque.pollLast();//队尾元素出队
                tmp.offerLast(node.val);
                //先右后左加入下层节点
                if(node.right != null)deque.offerFirst(node.right);
                if(node.left != null)deque.offerFirst(node.left);
            }
            res.add(tmp);//当前层打印结果添加到结果列表
        }
        return res;
    }
}

复杂度分析

同方法一

方法三-层序遍历+倒序

算法思路

将偶数层中的元素倒序

具体代码

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        Deque<TreeNode> deque = new LinkedList<>();//双端队列初始化
        List<List<Integer>> res = new ArrayList<>();//结果列表初始化
        if(root != null)deque.offerLast(root);//根节点尾部入队
        while(!deque.isEmpty()){
            //打印奇数层
            LinkedList<Integer> tmp = new LinkedList<>();//临时列表,存储当前层的打印结果
            for(int i = deque.size(); i > 0; i--){
                TreeNode node = deque.pollFirst();//队首元素出队
                tmp.offerLast(node.val);
                //加入下层节点
                if(node.left != null)deque.offerLast(node.left);
                if(node.right != null)deque.offerLast(node.right);
            }
            if(res.size() % 2 == 1)Collections.reverse(tmp);//偶数层倒序
            res.add(tmp);//当前层打印结果添加到结果列表
        }
        return res;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),n 为二叉树节点总数。因为 BFS 需要循环 n 次,占用 O ( n ) O(n) O(n);一共进行了少于 n 个节点的倒序操作,占用 O ( n ) O(n) O(n)。
  • 空间复杂度: O ( n ) O(n) O(n),因为在最坏情况下,即,树为满二叉树时,最多会有 n / 2 n/2 n/2 个节点同时在队列 d e q u e deque deque 中,占用了 O ( n ) O(n) O(n) 大小的额外空间。
上一篇:20. 有效的括号


下一篇:1425. 带限制的子序列和