【路飞】二叉树前序遍历&&N叉树前序遍历&&翻转二叉树&&二叉树的3道层序遍历题

2,012 阅读4分钟

记录 6 道算法题

二叉树前序遍历

leetcode-cn.com/problems/bi…


简单的递归就能实现,顺序是 根左右

    function preorderTraversal(root, result = []) {
        if (!root) return result
        result.push(root.val)
        preorderTraversal(root.left, result)
        preorderTraversal(root.right, result)
        return result
    }

N叉树前序遍历

leetcode-cn.com/problems/n-…


有两种办法,一种是递归,一种是迭代。

递归比较简单,和二叉树前序遍历没有区别,只是二叉树可以直接传 root.leftroot.right。而N叉树的子节点个数是不确定的,需要对 children 进行循环。

    function preorder(root, result = []) {
        if (!root) return result
        result.push(root.val)
        // 遍历收集
        if (root.children) {
          root.children.forEach(child => preorder(child, result))
        }
        return result
    }

迭代和二叉树的区别也是子节点的不确定。递归是用函数调用栈,隐藏了栈的使用,迭代也可以用一个栈来实现。把节点推入数组里,用的时候弹出来,要保持栈顶是当前遍历到的某个节点。可以倒着将节点推入,即先推children的最后一个节点。这样在栈顶的就是children最左边的节点。

    function preorder(root) {
        if (!root) return []
        const stack = [root]
        const result = []
        while (stack.length) {
          let node = stack.pop()
          result.push(node.val)
          if ((node = node.children)) {
              // 倒着推入
            for (let i = node.length - 1; i >= 0; i--) {
              stack.push(node[i])
            }
          }
        }
        return result
    }

翻转二叉树

226. 翻转二叉树 - 力扣(LeetCode) (leetcode-cn.com)


只要遍历每一个节点把 left 和 right 进行调转就行

    function invertTree(root) {
        if (!root) return root
        const temp = root.left
        root.left = root.right
        root.right = temp
        invertTree(root.left)
        invertTree(root.right)
        return root
    }

从上到下打印二叉树 ii

leetcode-cn.com/problems/co…


要求是一层层打印二叉树,所以肯定是用到了层序遍历。但是遍历到的每个节点都将他们的left right 推入同一个数组,重点是每一层的分界在哪。

    function levelOrder(root) {
        if (!root) return []
        const result = []
        let stack = [root]
        while (stack.length) {
          const temp = []
          // 重点是怎么让每一层有一个区分。这里比较巧妙的地方是,
          // 每一次 while 都是一层,把这时候的stack 计个数,
          // 就区分出了每一层
          for (let i = stack.length; i > 0; i--) {
            const node = stack.shift()
            temp.push(node.val)
            if (node.left) {
              stack.push(node.left)
            }

            if (node.right) {
              stack.push(node.right)
            }
          }
          result.push(temp)
        }
        return result
    }

二叉树的层序遍历 ii

leetcode-cn.com/problems/bi…


这道题要求是从底层向上一层层记录,其实只要正常的层序遍历,然后把每一层结果都推入到数组的开头就可以了。

在这之前先讲讲层序遍历吧。层序遍历是广度优先,递归是深度优先。意味着广度是从上面的节点,扫描完,然后再扫描下面的节点。

通常的做法是 将节点推入数组,然后每次都从数组的开头取值,像队列一样。因为每次都会推入节点的 left 和 right。所以在某一层的最后一个时,它是数组的开头。它的下一个就是这一层第一个节点的 left。大概是下面这种感觉

         a
      b    c
   d   e     f
   
   第一次 [a], shift() 拿到 a,将 a.left a.right 推入数组,现在数组里是 [b, c]
   第二次 [b, c], shift(), 拿到 b,将 b.left b.right 推入数组,现在数组是 [c. d, e]
   第三次 [c, d, e], shift(),拿到 c,将 c.left, c.right 推入数组。现在数组是 [d, e, f]
   然后一种重复,直到数组长度为0。 这时候所有节点都读了一遍

可以看到,当第三次的时候,已经是第二层的节点了。

然后每一层的边界怎么区分出来呢。就要用到一个临时数组。将 left right 推入到临时的数组。等 队列数组为0时,代表已经收集完下一层的节点。就将 临时数组赋值给队列数组就可以了。

    function levelOrderBottom(root) {
        if (!root) return []
        let stack = [root]
        const result = []

        while (stack.length) {
          const temp = []
          // 和上一题的思路一样,将当前的长度作为边界的标记。
          for (let i = stack.length; i > 0; i--) {
            const node = stack.shift()
            temp.push(node.val)
            node.left && stack.push(node.left)
            node.right && stack.push(node.right)
          }
          // 插入到开头,最后得到的就是从底层到第一层的结果了
          result.unshift(temp)
        }
        return result
    }

二叉树的锯齿形层序遍历

leetcode-cn.com/problems/bi…


要求像蛇形一样,每一层的方向相反。其实层序遍历的方法不会改变,还是一层层的推入数组,但是可以在输出的结果数组里面做文章。

    function zigzagLevelOrder(root) {
        if (!root) return []
        const stack = [root]
        const result = []
        // 这里进行了改造
        let a = 'push'

        while (stack.length) {
          const temp = []
          for (let i = stack.length; i > 0; i--) {
            const node = stack.shift()
            // 通过切换 push 和 unshift,改变方向,实现蛇形
            temp[a](node.val)
            node.left && stack.push(node.left)
            node.right && stack.push(node.right)
          }
          // 每经过一层变一次
          a = a === 'push' ? 'unshift' : 'push'
          result.push(temp)
        }
        return result
    }

结束