LeetCode 103. 二叉树的锯齿形层序遍历:广度优先搜索详解

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

题目来源

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

题目分析

在这道题目中,我们需要对给定的二叉树进行锯齿形层序遍历,并返回每一层节点值的列表。具体题目描述如下:

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

题目难度

  • 难度:中等

题目标签

  • 标签:树、广度优先搜索、二叉树

题目限制

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

解题思路

要解决这个问题,我们可以继续使用广度优先搜索 (BFS),代码跟102二叉树层序遍历很相似,不过这次我们需要在每一层结束时对节点的顺序进行调整。具体来说,奇数层的节点从左到右添加,偶数层的节点从右到左添加。

BFS 算法步骤

  1. 初始化队列:将根节点加入队列。
  2. 遍历每一层:对于队列中的每一层,记录当前层的节点数,并依次将节点从队列中移出,按需将节点值反转。
  3. 加入子节点:将当前节点的左右子节点(如果存在)加入队列,等待下一层遍历。
  4. 反转节点顺序:如果当前层数为奇数,反转该层的节点值。
  5. 保存当前层结果:将当前层的结果列表加入最终结果列表中。
  6. 返回结果:返回包含所有层节点值的结果列表。

代码实现

以下是实现二叉树锯齿形层序遍历的Java代码:

/**
 * 103. 二叉树的锯齿形层序遍历
 * @param root 二叉树根节点
 * @return ans 二叉树按锯齿形层序遍历得到的节点值
 */
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
    // 结果集
    List<List<Integer>> ans = new ArrayList<>();
    // 如果根节点为空,则返回空结果集
    if (root == null) {
        return ans;
    }
    // 队列
    Deque<TreeNode> queue = new LinkedList<>();
    // 根节点入队
    queue.add(root);
    // 当队列不为空时,处理每一层的节点
    while (!queue.isEmpty()) {
        List<Integer> vals = new ArrayList<>();
        for (int i = queue.size(); i > 0; i--) {
            TreeNode node = queue.removeFirst();
            vals.add(node.val);
            // 左右子树不为空入队
            if (node.left != null) {
                queue.add(node.left);
            }
            if (node.right != null) {
                queue.add(node.right);
            }
        }
        // 如果当前层为奇数层,则将vals反转
        if (ans.size() % 2 == 1) {
            Collections.reverse(vals);
        }
        // 将本层的节点值加入结果集
        ans.add(vals);
    }
    return ans;
}

代码解读

  • 初始化队列:首先,判断根节点是否为空,如果为空,则返回空列表。
  • 处理每一层节点:使用 while 循环,当队列不为空时,依次处理每一层的节点。对于每一层,将当前层节点的值存入 vals 列表中。
  • 反转奇数层:在将 vals 添加到结果集之前,检查当前层是否为奇数层,如果是,则反转 vals 列表中的节点顺序。
  • 返回结果:最后返回包含所有层结果的 ans 列表。

性能分析

  • 时间复杂度O(n),其中 n 是树中节点的总数,因为我们需要访问树中的每个节点一次。
  • 空间复杂度O(n),因为在最坏情况下,队列中可能需要存储一整层的节点。

测试用例

你可以使用以下测试用例来验证代码的正确性:

TreeNode root = new TreeNode<>(1);
root.left = new TreeNode<>(2);
root.right = new TreeNode<>(3);
root.left.left = new TreeNode<>(4);
root.left.right = new TreeNode<>(5);
root.right.left = new TreeNode<>(6);
root.right.right = new TreeNode<>(7);
List<List<Integer>> result = zigzagLevelOrder(root);
System.out.println(result); 
// 输出: [[1], [3, 2], [4, 5, 6, 7]]

扩展讨论

双端队列的优化写法

while (!queue.isEmpty()) {
            List<Integer> vals = new ArrayList<>();
            for (int i = queue.size(); i > 0; i--) {
                TreeNode<Integer> node = queue.removeFirst();
                //vals.add(node.val);
                //双端队列写法
                // 如果ans的层数为奇数,则将当前节点的值添加到双端队列的开头,否则添加到双端队列的末尾
                if (ans.size() % 2 == 1) {
                    vals.addFirst(node.val);
                } else {
                    vals.addLast(node.val);
                }
                // 左右子树不为空入队
                if (node.left != null) {
                    queue.add(node.left);
                }
                if (node.right != null) {
                    queue.add(node.right);
                }
            }

递归实现

除了使用迭代的方式来实现锯齿形层序遍历,还可以使用递归的方法实现。递归的思想与BFS相似,但需要在遍历过程中维护当前的层数来决定遍历方向。

总结

通过这道题目,我们进一步掌握了如何使用广度优先搜索来实现更复杂的二叉树遍历方法。锯齿形层序遍历作为层序遍历的扩展,增加了对节点顺序的控制,提供了一种更灵活的遍历方式。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值