leetcode
leetcode 101 ~ 150
二叉树的锯齿形层序遍历

二叉树的锯齿形层序遍历

难度:

标签:

题目描述

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

 

示例 1:

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

示例 2:

输入:root = [1]
输出:[[1]]

示例 3:

输入:root = []
输出:[]

 

提示:

  • 树中节点数目在范围 [0, 2000]
  • -100 <= Node.val <= 100

代码结果

运行时间: 32 ms, 内存: 15.1 MB


// Solution using Java Stream (though not the typical use case for streams)
// The stream API is not well-suited for this problem due to its stateful nature.
// We will use traditional methods but demonstrate where streams might be applied.
import java.util.*;
import java.util.stream.Collectors;
 
public class ZigzagLevelOrderStream {
    public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        if (root == null) return result;
 
        Deque<TreeNode> deque = new LinkedList<>();
        deque.offer(root);
        boolean leftToRight = true;
 
        while (!deque.isEmpty()) {
            int size = deque.size();
            List<Integer> level = new ArrayList<>(size);
            for (int i = 0; i < size; i++) {
                TreeNode node = deque.poll();
                level.add(node.val);
                if (node.left != null) deque.offer(node.left);
                if (node.right != null) deque.offer(node.right);
            }
            if (!leftToRight) {
                Collections.reverse(level); // Reverse the list if needed
            }
            result.add(level);
            leftToRight = !leftToRight;
        }
        return result;
    }
}
 
// TreeNode class definition for the binary tree structure
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}

解释

方法:

这个题解采用了 BFS (广度优先搜索) 的思路。使用一个双端队列保存每一层的节点,然后按照 Z 字形的顺序遍历输出节点值。具体来说: 1. 首先判断根节点是否为空,如果为空则直接返回空列表。 2. 创建一个结果列表 result 和一个双端队列 q,并将根节点加入队列。 3. 初始化 l2r 标志为 True,表示从左到右遍历。 4. 当队列不为空时,进行如下操作: a. 获取当前层的节点数 size。 b. 创建一个大小为 size 的列表 floor,用于保存当前层的节点值。 c. 遍历当前层的所有节点: - 从队列的左端弹出一个节点。 - 根据 l2r 标志确定节点值在 floor 中的索引:如果 l2r 为 True,索引为 i;否则索引为 size-1-i。 - 将节点值放入 floor 的对应索引位置。 - 如果节点有左子节点,将左子节点加入队列。 - 如果节点有右子节点,将右子节点加入队列。 d. 将 l2r 标志取反。 e. 将当前层的节点值列表 floor 加入结果列表 result。 5. 返回结果列表 result。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么选择广度优先搜索(BFS)而不是深度优先搜索(DFS)来进行这种锯齿形的层序遍历?
广度优先搜索(BFS)可以自然地按层遍历二叉树,这为实现按层的锯齿形遍历提供了便利。使用BFS时,我们可以轻松地控制节点的访问顺序,并且可以在每层遍历完成后立即处理或修改节点的存储顺序,以实现锯齿形输出。而深度优先搜索(DFS)虽然也可以进行层级遍历,但实现起来需要额外的努力和数据结构来追踪每个节点的层级信息,并且在每层的访问顺序控制上不如BFS直接和自然。
🦆
在双端队列中存储节点而不是单纯使用两个栈来实现锯齿形遍历的原因是什么?
双端队列提供了在两端都能高效插入和删除的能力,这使得它非常适合实现锯齿形遍历。使用双端队列,我们可以通过简单地调整从队列哪一端弹出节点来轻松地切换遍历的方向,这样就可以在遍历时动态地改变方向而无需额外的数据结构。相对而言,使用两个栈虽然也可以实现方向的切换,但在进行节点的层级管理和子节点的正确添加顺序上会更加复杂和不直观。
🦆
在算法中,你如何确保在最末尾的层也正确地按照锯齿形顺序添加节点值?
在算法中,通过一个布尔变量`l2r`来控制每层节点值添加到结果列表的顺序。在每层的开始之前,这个变量会根据其当前值(表示当前遍历方向)来确定节点值在列表中的添加顺序。每完成一层的遍历后,`l2r`的值会被取反,从而改变下一层的遍历方向。这保证了即使在最末尾的层,节点值的添加顺序也会根据之前层的遍历方向正确地调整,从而实现正确的锯齿形顺序。
🦆
对于变量`l2r`,如果在每层迭代开始之前不更新它的值会怎样影响输出结果?
如果不在每层迭代开始之前更新变量`l2r`的值,那么所有层的节点都会按照同一个方向(要么都是从左到右,要么都是从右到左)来添加到结果列表中。这样就无法实现锯齿形遍历,因为锯齿形遍历的特点是每一层的遍历方向都与上一层相反。因此,正确地更新`l2r`对于实现题目要求的锯齿形输出是必须的。

相关问题

二叉树的层序遍历

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

 

示例 1:

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

示例 2:

输入:root = [1]
输出:[[1]]

示例 3:

输入:root = []
输出:[]

 

提示:

  • 树中节点数目在范围 [0, 2000]
  • -1000 <= Node.val <= 1000