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

leetcode

 

解题思路

锯齿形层序遍历是二叉树层序遍历的变种,要求按层遍历节点,但相邻层的遍历方向交替变化:第0层(根节点层)从左到右,第1层从右到左,第2层再从左到右,以此类推。核心思路是:

  1. ​​基于BFS的层序遍历​​:使用队列实现广度优先搜索,按层处理节点。
  2. ​​方向交替控制​​:通过层数奇偶性(从0开始计数)决定当前层的输出方向:
    • 偶数层(0、2、4...):节点值按正常顺序存储
    • 奇数层(1、3、5...):反转节点值列表
  3. ​​分层处理​​:每次处理一层节点,记录当前队列长度确保分层。

区别于普通层序遍历,锯齿形遍历需根据层数动态调整节点值存储顺序。

关键步骤

  1. ​​初始化队列​​:根节点入队(非空时)
  2. ​​层数标记​​:初始化level=0(根节点为第0层)
  3. ​​BFS循环​​:
    • 获取当前层节点数levelSize
    • 创建临时切片levelVals存储当前层节点值
    • 遍历当前层节点:
      • 队首节点出队,值存入levelVals
      • 左/右子节点非空时入队
    • level为奇数:反转levelVals(双指针交换)
    • levelVals加入结果集,层数level++
  4. ​​返回结果​​:二维切片,每层一个子切片

代码实现

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))

关键点总结

  1. ​​队列核心作用​​:先进先出特性保证层级顺序
  2. ​​分层控制​​:levelSize记录当前层节点数,内循环精准控制
  3. ​​方向交替​​:level%2判断奇偶层,决定是否反转列表
  4. ​​高效反转​​:双指针交换(O(k)时间,O(1)空间)
  5. ​​空树处理​​:初始判断避免空指针异常
  6. ​​结果结构​​:每层独立切片嵌套形成锯齿形输出
posted @ 2025-06-08 12:37  云隙之间  阅读(52)  评论(0)    收藏  举报