乐趣区

关于前端:记一次面试被问-求二叉树每层最大值构造二叉树验证优化循环层数-的解答过程

背景

写这篇文章次要是记录一下本人面试被问到的这个问题: 求二叉树每层最大值 到 结构一颗二叉树去验证 到进一步优化循环层数 的解答过程。(面试常见套路,手写 -> 优化 / 其余解法 / 工夫空间复杂度剖析)

工夫一久就会遗记怎么写,下次又得想半天,而面试必定不会让现场想半天的,所以须要熟记思路。

这个题目源于我写的字节跳动实习的面经 https://segmentfault.com/a/1190000038543869,将解答过程写进面经外面会比拟长,所以独自抽出来总结一下。


1. 求二叉树每层的最大节点

这个办法比拟常见,记得数据结构书中二叉树层序遍历的代码示例就是这个办法,leetcode 的题解也多是两层循环。

ps:如果一开始就写出一层循环那当然不会有后续让优化的问题了。但举荐写这种,后续大多会被问到怎么用一层实现 (我小米和字节都被问到了)。这时再装作想一想而后写进去岂不是更显得本人应变能力强,有算法根底而不是背进去的?

var largestValues = function(root) {if(!root) return []
     const res = []    // 最终输入的后果,寄存每层的最大值
     let queue = [root]     // 根节点入队
     while(queue.length) {
         let len = queue.length
         let tmp = []   // 寄存以后层的所有节点的值
         while(len) {   // 此处的 len 记录的是以后层的节点数,为 0 代表遍历完以后层的节点,开始遍历下一层
             let curr = queue.shift()
             if(curr.left) queue.push(curr.left)
             if(curr.right) queue.push(curr.right)
             tmp.push(curr.val)
             len--
         }
         res.push(Math.max(...tmp))
     }
     return res
}

2. 结构一颗二叉树, 用于验证咱们写的求每层最大值的函数

// 二叉树的节点的构造方法
 function TreeNode(val, left, right) {
         this.val = val
         this.left = null
         this.right = null
  }
  
  // 接下来咱们构建一颗第一层为 1,第二层为 2,3,第三层为 4,5,6 的二叉树
  let p1 = new TreeNode(1)
  let p2 = new TreeNode(2)
  let p3 = new TreeNode(3)
  let p4 = new TreeNode(4)
  let p5 = new TreeNode(5)
  let p6 = new TreeNode(6)
  
  // 将这些节点相互连接起来
  p1.left = p2
  p1.right = p3
  p2.left = p4
  p2.right = p5
  p3.left = p6

  // 验证
  console.log(largestValues(p1));   // 输入 [1, 3, 6]

3. 循环层数优化:将刚刚写的求二叉树每层最大值的办法中的两层循环改为一层

思路:在后面的办法中,咱们内层循环的作用是记录以后层的节点数, 让咱们晓得什么时候本层节点遍历完。既然少了一层循环,那咱们就只能用额定空间去记录下一层节点了

 var largestValuesImprove = function(root) {if(!root) return []
        const res = []    // 最终输入的后果,寄存每层的最大值
        let queue = [root]     // 寄存以后层的节点
        let nextLevel = []   // 寄存下一层的节点
        let tmp = []
        while(queue.length>0 || nextLevel.length>0) {if(queue.length===0) {   // 以后层遍历完
                queue = nextLevel   // 取下一层
                nextLevel = []
                res.push(Math.max(...tmp))
                tmp = []}
            let curr = queue.shift()
            tmp.push(curr.val)
            if(curr.left) nextLevel.push(curr.left)
            if(curr.right) nextLevel.push(curr.right)
        }
        // 这里肯定要留神最初一次跳出循环时没有走 if 语句,须要再把最初一层的值放入 res
        res.push(Math.max(...tmp))
        return res
 }
 
 // 验证
 console.log(largestValuesImprove(p1));

残缺代码

     // 1. 求二叉树每层的最大节点
     var largestValues = function(root) {if(!root) return []
        const res = []    // 最终输入的后果,寄存每层的最大值
        let queue = [root]     // 根节点入队
        while(queue.length) {
            let len = queue.length
            let tmp = []   // 寄存以后层的所有节点的值
            while(len) {   // 此处的 len 记录的是以后层的节点数,为 0 代表遍历完以后层的节点,开始遍历下一层
                let curr = queue.shift()
                if(curr.left) queue.push(curr.left)
                if(curr.right) queue.push(curr.right)
                tmp.push(curr.val)
                len--
            }
            res.push(Math.max(...tmp))
        }
        return res
     }

     // 2. 结构一颗二叉树, 用于验证咱们写的求每层最大值的函数
     function TreeNode(val, left, right) {    // 节点的构造方法
         this.val = val
         this.left = null
         this.right = null
     }
    // 接下来咱们构建一颗第一层为 1,第二层为 2,3,第三层为 4,5,6 的二叉树
    let p1 = new TreeNode(1)
    let p2 = new TreeNode(2)
    let p3 = new TreeNode(3)
    let p4 = new TreeNode(4)
    let p5 = new TreeNode(5)
    let p6 = new TreeNode(6)
    // 将这些节点相互连接起来
    p1.left = p2
    p1.right = p3
    p2.left = p4
    p2.right = p5
    p3.left = p6

    // 3. 验证
    console.log(largestValues(p1));   // 输入 [1, 3, 6]


    // 4. 循环层数优化:将咱们刚刚写求二叉树每层的最大值中两层循环改为一层
    // 思路:在后面的办法中,咱们内层循环的作用是记录以后层的节点数, 让咱们晓得什么时候本层节点遍历完。// 既然少了一层循环,那咱们就只能用额定空间去记录下一层节点了
    var largestValuesImprove = function(root) {if(!root) return []
        const res = []    // 最终输入的后果,寄存每层的最大值
        let queue = [root]     // 寄存以后层的节点
        let nextLevel = []   // 寄存下一层的节点
        let tmp = []
        while(queue.length>0 || nextLevel.length>0) {if(queue.length===0) {   // 以后层遍历完
                queue = nextLevel   // 取下一层
                nextLevel = []
                res.push(Math.max(...tmp))
                tmp = []}
            let curr = queue.shift()
            tmp.push(curr.val)
            if(curr.left) nextLevel.push(curr.left)
            if(curr.right) nextLevel.push(curr.right)
        }
        // 这里肯定要留神最初一次跳出循环时没有走 if 语句,须要再把最初一层的值放入 res
        res.push(Math.max(...tmp))
        return res
     }
     console.log(largestValuesImprove(p1));
退出移动版