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 扩展
  • 树形配置批量读取
  • 大模型多轮逻辑树展开

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

相关推荐
Black蜡笔小新6 小时前
自动化AI算法训练服务器DLTM助力医学影像分析进入AI智能分析新时代
人工智能·算法·自动化
手写码匠7 小时前
深入解析大模型架构之争:全能通用模型 vs 领域专精模型
人工智能·深度学习·算法·aigc
浅念-7 小时前
LeetCode 回溯算法题——综合练习
数据结构·c++·算法·leetcode·职场和发展·深度优先·dfs
列星随旋8 小时前
线段树和树状数组的学习
学习·算法
圣保罗的大教堂8 小时前
leetcode 61. 旋转链表 中等
leetcode
我爱cope9 小时前
【Agent智能体4 | 智能体AI的应用】
数据库·人工智能·职场和发展
全糖可乐气泡水10 小时前
Codex适配国产信创环境安装部署与技术适配全解析
开发语言·git·python·算法·百度
h_a_o777oah10 小时前
状态机+划分型 DP :深度解析K-划分问题下 DP 状态的转移逻辑(洛谷P2679 P2331 附C++代码)
c++·算法·动态规划·acm·状态机dp·划分型dp·滚动数组优化
05候补工程师10 小时前
从算法理想向工程现实的跨越:SLAM 核心架构、思维误区与 Nav2 实战避坑指南
人工智能·算法·安全·架构·机器人