LeetCode 429 - N 叉树的层序遍历


文章目录

摘要

这道题其实非常"树的基本功"。我们要对一棵 N 叉树(每个节点可以有任意数量的子节点) 做层序遍历,也就是 BFS,从上到下、一层一层扫过去,最后输出成一个二维数组。

虽然思路很基础,但在实际项目里,也经常会遇到需要按层处理节点的情况,比如:

  • UI 结构的按层遍历(菜单、组件树)
  • 配置树按层读取
  • 文件结构扫描
  • 大模型 Prompt Tree 的逐级展开

所以,除了 LeetCode,本题本质是一类通用场景,非常值得系统掌握。

下面我们会从题目、代码实现、细节解析、示例运行等角度,带你把这个 BFS 方案拆得明明白白。

描述

题目给你一棵 N 叉树,让你输出它的层序遍历结果。

也就是:

  • 第一层:树根
  • 第二层:树根的所有子节点
  • 第三层:第二层所有节点的子节点
  • 依此类推

输入是按层序序列化格式给的,比如:

txt 复制代码
[1,null,3,2,4,null,5,6]

null 表示"这一层的子节点结束"。

因为我们写 Swift,所以要自己定义 Node 结构:

swift 复制代码
public class Node {
    public var val: Int
    public var children: [Node]
    public init(_ val: Int) {
        self.val = val
        self.children = []
    }
}

我们的任务很直接:返回一个二维数组,每一层就是一行。

题解答案

核心思路就是 广度优先搜索(BFS)

步骤非常固定:

  1. 判断 root 是否为空,是则返回空数组。

  2. 准备一个队列,把 root 放进去。

  3. 每次循环处理一层:

    • 记录当前队列的长度(这一层节点的数量)
    • 逐个弹出节点,把 node.val 放入这一层的数组
    • 把它的 children 全部加入队列
  4. 直到队列为空,遍历结束。

最终输出所有层的结果。

题解代码分析

下面给出可直接运行的 Swift 代码,并在后面逐行解析:

swift 复制代码
import Foundation

// N 叉树节点定义
public class Node {
    public var val: Int
    public var children: [Node]
    public init(_ val: Int) {
        self.val = val
        self.children = []
    }
}

// 层序遍历实现
class Solution {
    func levelOrder(_ root: Node?) -> [[Int]] {
        guard let root = root else { return [] }

        var result: [[Int]] = []
        var queue: [Node] = [root]

        while !queue.isEmpty {
            let size = queue.count
            var level: [Int] = []

            for _ in 0..<size {
                let node = queue.removeFirst()
                level.append(node.val)

                for child in node.children {
                    queue.append(child)
                }
            }

            result.append(level)
        }

        return result
    }
}

代码拆解说明

1. 根节点判空

swift 复制代码
guard let root = root else { return [] }

非常常见的防御式编程,避免 root 为 nil 导致后续逻辑无法执行。

2. 用数组模拟队列

swift 复制代码
var queue: [Node] = [root]

Swift 标准库没有官方 Queue,所以我们用数组加 removeFirst() 来模拟。虽然复杂度不是最优,但是在这里完全够用。

如果你真的遇到性能极端要求,可以用自己实现的 Deque 结构,但 LeetCode 已经绰绰有余。

3. BFS 主体逻辑

swift 复制代码
while !queue.isEmpty {
    let size = queue.count
    var level: [Int] = []

关键点是这行:

txt 复制代码
let size = queue.count

它告诉我们"这一层一共有多少节点",防止后续入队操作影响层的边界。

4. 遍历这一层

swift 复制代码
for _ in 0..<size {
    let node = queue.removeFirst()
    level.append(node.val)

每次从队列头部拿出一个节点,并把值存进当前层。

5. 将子节点全部入队

swift 复制代码
for child in node.children {
    queue.append(child)
}

N 叉树的关键就是 children 是一个数组,所以可以有不限数量的子节点。

示例测试及结果

我们来写一段可运行的 Demo 来验证逻辑。

下面构造两棵树,对照题目中的例子。

swift 复制代码
func buildExampleTree1() -> Node {
    let root = Node(1)
    let node3 = Node(3)
    let node2 = Node(2)
    let node4 = Node(4)
    node3.children = [Node(5), Node(6)]
    root.children = [node3, node2, node4]
    return root
}

let example1 = buildExampleTree1()
let sol = Solution()
print(sol.levelOrder(example1))

运行结果

txt 复制代码
[[1], [3, 2, 4], [5, 6]]

完全符合示例 1。

再来一个更复杂的树示例(简化版示例 2):

swift 复制代码
func buildExampleTree2() -> Node {
    let root = Node(1)

    let level2 = [Node(2), Node(3), Node(4), Node(5)]
    root.children = level2

    level2[1].children = [Node(6), Node(7)]
    level2[2].children = [Node(8)]
    level2[3].children = [Node(9), Node(10)]

    return root
}

let example2 = buildExampleTree2()
print(sol.levelOrder(example2))

运行结果

txt 复制代码
[[1], [2, 3, 4, 5], [6, 7, 8, 9, 10]]

也完全符合期望。

时间复杂度

O(N)

N 是节点总数。

每个节点都会入队 / 出队一次,并被处理一次,所以整体是线性的。

空间复杂度

O(N)

主要来自:

  • 队列的存储
  • 输出结果本身

在最宽的一层,队列可能临时存下大量节点。

总结

这一题的解法非常经典: BFS 层序遍历。它的难度不在算法,而在于你需不需要对 N 叉树的结构适应一下。

如果用二叉树的思路迁移过来,基本可以无缝写出来。

在实际项目里,层序遍历也非常常见,比如:

  • 从 UI 结构按层级序列化
  • 图结构按 level 扩展
  • 树形配置批量读取
  • 大模型多轮逻辑树展开

所以这道题非常值得你熟练掌握它的代码结构。

相关推荐
星释1 小时前
Rust 练习册 32:二分查找与算法实现艺术
开发语言·算法·rust
zl_vslam2 小时前
SLAM中的非线性优-3D图优化之四元数在Opencv-PNP中的应用(五)
人工智能·算法·计算机视觉
机器学习之心2 小时前
经典粒子群优化算法PSO-LSTM回归+SHAP分析+多输出+新数据预测!Matlab代码实现
算法·lstm·pso-lstm·shap分析
007php0072 小时前
Redis面试题解析:Redis的数据过期策略
java·网络·redis·缓存·面试·职场和发展·php
小青龙emmm3 小时前
2025级C语言第四次周测题解
c语言·开发语言·算法
树在风中摇曳3 小时前
【牛客排序题详解】归并排序 & 快速排序深度解析(含 C 语言完整实现)
c语言·开发语言·算法
minji...3 小时前
算法---模拟/高精度/枚举
数据结构·c++·算法·高精度·模拟·枚举
执笔论英雄4 小时前
【大模型训练】forward_backward_func返回多个micro batch 损失
开发语言·算法·batch
草莓熊Lotso5 小时前
《算法闯关指南:优选算法--模拟》--41.Z 字形变换,42.外观数列
开发语言·c++·算法