记一次面试被问 【求二叉树每层最大值->构造二叉树验证->优化循环层数】 的解答过程

背景

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

时间一久就会忘记怎么写,下次又得想半天,而面试肯定不会让现场想半天的,所以需要熟记思路。

这个题目源于我写的字节跳动实习的面经 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));

你可能感兴趣的:(记一次面试被问 【求二叉树每层最大值->构造二叉树验证->优化循环层数】 的解答过程)