[路飞]_二叉树的锯齿形层序遍历

749 阅读3分钟

「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战

leetcode-103 二叉树的锯齿形层序遍历
b站视频

题目介绍

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

示例1

image.png

输入: root = [3,9,20,null,null,15,7]
输出: [[3],[20,9],[15,7]]

示例2

输入: root = [1]
输出: [[1]]

示例3

输入: root = []
输出: []

提示:

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

解题思路

本文将讲解此题的两种解题思路

思路一

第一种解题思路是利用深度优先的方法,先遍历完整棵树,并将每一层的节点从左到右放在最终结果数组的相应位置,然后对于奇数层的节点数组进行翻转,而偶数层的数组则保持原来从左到右的位置不变

解题步骤

  1. 判断如果这棵树是空树,则直接返回 []
  2. 定义存放最后结果的数组 ans,定义表示每一层层数的变量 k
  3. 如果结果数组 ans 在当前层数的下标位置为 undefined,那么将 [] 放置到当前下标对应的位置上
  4. 否则将当前节点的值 push 到与当前层数一致的下标的数组中
  5. 如果当前节点有孩子节点,则对其孩子节点执行 3-4 的操作,并将当前层数 k + 1 传递到孩子节点的递归上,表示孩子节点所在的层数
  6. 重复 3-5 的操作,直到遍历完整棵树
  7. 此时的 ans 为每一层从左到右遍历的结果,需要将奇数层的数组进行翻转

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

解题代码

var zigzagLevelOrder = function(root) {
    // 如果是空树,则返回 []
    if (!root) return []
    // 定义存放最终结果的数组
    const ans = []
    // 定义表示当前层数的变量
    let k = 0
    _levelOrder(root, k, ans)
    // 对奇数层的数组进行翻转,偶数层保持不变
    return ans.map((v, i) => {
        if (i % 2 === 1) {
            return v.reverse()
        }
        return v
    })
};

var _levelOrder = function(root, k, ans) {
    // 如果当前位置没有值,则放置 []
    if (!ans[k]) ans[k] = []
    // 往当前位置的数组中插入节点的值
    ans[k].push(root.val)
    // 如果有左孩子则递归遍历左子树
    root.left && _levelOrder(root.left, k + 1, ans)
    // 如果有右孩子则递归遍历右子树
    root.right && _levelOrder(root.right, k + 1, ans)
}

解法二

第二种做法是利用队列的特性,将每一层的节点依次入队到节点队列中,然后依次出队,如果当前节点有孩子节点,则将左右孩子依次入队,同时维持一个标志位,表示当前层的节点需要从左到右还是从右到左插入结果数组中

解题步骤

  1. 判断如果当前是一棵空树,则直接返回 []
  2. 定义存放最后结果的数组 ans,定义存放节点的数组 nodeArr,并将根节点 root 先入队,定义标志位 sign ,如果 signfalse,说明当前层需要从左到右,否则则是从右到左
  3. 如果 nodeArr 不为空,获取当前数组的长度,即为当前层的节点个数,然后定义一个存放该层结果的数组 arr
  4. 将该层的节点依次出队,如果标志位为 false,则从后面压入数组,否则从前面压入数组
  5. 如果有左右孩子节点,则将左右孩子节点依次从后面压入 nodeArr 数组中
  6. 结束当前层节点的遍历之后,将标志位 sign 取反,并将当前层的结果 pushans
  7. 重复 3-6 的步骤,直到遍历完整棵树

二叉树的锯齿形层序遍历(1).gif

解题代码

var zigzagLevelOrder = function(root) {
    // 如果是空树,直接返回 []
    if (!root) return []
    // 定义存放最后结果的数组
    const ans = []
    // 定义存放节点的数组
    const nodeArr = [root]
    // 定义标志位,false表示从左往右,true表示从右往左
    let sign = false
    while (nodeArr.length) {
        // 获取当前层的节点数量
        const len = nodeArr.length
        const arr = []
        for (let i = 0; i < len; i++) {
            // 将当前层节点依次出队
            const node = nodeArr.shift()
            if (!sign) {
                // 如果为false,从后面插入数组
                arr.push(node.val)
            } else {
                // 如果为true,从前面插入数组
                arr.unshift(node.val)
            }
            // 如果有左孩子,将左孩子插入节点数组
            node.left && nodeArr.push(node.left)
            // 如果有右孩子,将右孩子插入节点数组
            node.right && nodeArr.push(node.right)
        }
        // 遍历完一层之后,改变sign的值
        sign = !sign
        // 将当前层的结果插入到结果数组中
        ans.push(arr)
    }
    return ans
};