leetcode
 
解题思路
锯齿形层序遍历是二叉树层序遍历的变种,要求按层遍历节点,但相邻层的遍历方向交替变化:第0层(根节点层)从左到右,第1层从右到左,第2层再从左到右,以此类推。核心思路是:
- 基于BFS的层序遍历:使用队列实现广度优先搜索,按层处理节点。
 
- 方向交替控制:通过层数奇偶性(从0开始计数)决定当前层的输出方向:
- 偶数层(0、2、4...):节点值按正常顺序存储
 
- 奇数层(1、3、5...):反转节点值列表
 
 
- 分层处理:每次处理一层节点,记录当前队列长度确保分层。
 
区别于普通层序遍历,锯齿形遍历需根据层数动态调整节点值存储顺序。
关键步骤
- 初始化队列:根节点入队(非空时)
 
- 层数标记:初始化
level=0(根节点为第0层) 
- BFS循环:
- 获取当前层节点数
levelSize 
- 创建临时切片
levelVals存储当前层节点值 
- 遍历当前层节点:
- 队首节点出队,值存入
levelVals 
- 左/右子节点非空时入队
 
 
- 若
level为奇数:反转levelVals(双指针交换) 
- 将
levelVals加入结果集,层数level++ 
 
- 返回结果:二维切片,每层一个子切片
 
代码实现
type TreeNode struct {
    Val   int
    Left  *TreeNode
    Right *TreeNode
}
func zigzagLevelOrder(root *TreeNode) [][]int {
    if root == nil {
        return [][]int{} // 空树直接返回空结果
    }
    // 初始化队列和结果集
    queue := []*TreeNode{root}
    var res [][]int
    level := 0 // 层数标记(0开始)
    for len(queue) > 0 {
        levelSize := len(queue) // 当前层节点数
        levelVals := make([]int, 0, levelSize)
        // 遍历当前层节点
        for i := 0; i < levelSize; i++ {
            node := queue[0]  // 队首出队
            queue = queue[1:] // 更新队列
            levelVals = append(levelVals, node.Val) // 存储节点值
            // 子节点入队(下一层)
            if node.Left != nil {
                queue = append(queue, node.Left)
            }
            if node.Right != nil {
                queue = append(queue, node.Right)
            }
        }
        // 奇数层反转节点值列表
        if level%2 == 1 {
            for i, j := 0, len(levelVals)-1; i < j; i, j = i+1, j-1 {
                levelVals[i], levelVals[j] = levelVals[j], levelVals[i]
            }
        }
        res = append(res, levelVals) // 加入结果集
        level++                      // 层数递增
    }
    return res
}
 
 
 
示例测试
func main() {
    // 示例1: [3,9,20,null,null,15,7]
    root1 := &TreeNode{Val: 3}
    root1.Left = &TreeNode{Val: 9}
    root1.Right = &TreeNode{Val: 20}
    root1.Right.Left = &TreeNode{Val: 15}
    root1.Right.Right = &TreeNode{Val: 7}
    fmt.Println(zigzagLevelOrder(root1)) // [[3] [20 9] [15 7]]
    // 示例2: 单节点
    root2 := &TreeNode{Val: 1}
    fmt.Println(zigzagLevelOrder(root2)) // [[1]]
    // 示例3: 空树
    var root3 *TreeNode
    fmt.Println(zigzagLevelOrder(root3)) // []
}
 
 
 
复杂度分析
| 操作 | 时间复杂度 | 空间复杂度 | 说明 | 
| BFS遍历 | 
O(n) | 
O(n) | 
n为节点总数,每个节点访问1次 | 
| 队列存储 | 
O(n) | 
O(w) | 
w为树最大宽度(最宽层节点数) | 
| 反转操作 | 
O(k) | 
O(1) | 
k为每层节点数,总和为O(n) | 
 
注:空间复杂度最坏情况为完美二叉树,叶子层节点数达⌈n/2⌉(约O(n))
关键点总结
- 队列核心作用:先进先出特性保证层级顺序
 
- 分层控制:
levelSize记录当前层节点数,内循环精准控制 
- 方向交替:
level%2判断奇偶层,决定是否反转列表 
- 高效反转:双指针交换(O(k)时间,O(1)空间)
 
- 空树处理:初始判断避免空指针异常
 
- 结果结构:每层独立切片嵌套形成锯齿形输出