【代码随想录 | day15】(JavaScript) 二叉树系列:层序遍历及相关题目(上)

135 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第10天,点击查看活动详情

  • 二叉树的层序遍历
  • 107.二叉树的层序遍历 II
  • 二叉树的右视图
  • 二叉树的层平均值

层序遍历

什么是层序遍历?先来看看例子

给你一个二叉树,[3,9,20,null,null,15,7]

层序.jpg

让你输出 !

层序遍历的结果.jpg

知道二叉树的层序遍历,可以一口气打完以下十题:

102.二叉树的层序遍历

题目链接:102. 二叉树的层序遍历

遍历思路:借助队列来实现,队列先进先出,符合一层一层遍历的逻辑,而是用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。

  • 首先遍历第一层的节点,记录根节点的val,然后放入队列中,同时记录队列的length。
  • 弹出根节点,然后依次将上述根节点的左节点val 、右节点val 放入队列中
  • 只有队列的length为0时,才开始遍历下一层
 var levelOrder = function(root) {
     //二叉树的层序遍历
     let res = [], queue = []; // res存放结果,queue是咱们借助的队列
     queue.push(root);
     if(root === null) {
         return res;
     }
     while(queue.length !== 0) {
         // 记录当前层级节点数
         let length = queue.length;
         //存放每一层的节点 
         let curLevel = [];
         for(let i = 0; i < length; i++) {
             let node = queue.shift();
             curLevel.push(node.val);
             // 存放当前层下一层的节点
             node.left && queue.push(node.left);
             node.right && queue.push(node.right);
         }
         //把每一层的结果放到结果数组
         res.push(curLevel);
     }
     return res;
 };

拿测试用例 root = [3,9,20,null,null,15,7] 来解释一些问题

  • 函数里面第二行queue.push(root); 解读:执行完这一句话, queue 的值变为 [ [3,9,20,null,null,15,7] ];queue的长度为1 。
  • 第一次执行let node = queue.shift(); 后, node 为 [3,9,20,null,null,15,7] ,此时queue的长度为 0。这个就是弹出每一层根节点的操作。
  • curLevel.push(node.val); 第一次进行这个操作后,curLevel 的值为 [3] ,后续把 curLevel push进 res 后,res 就是一个二维数组。
  • 当node的左右子节点存在时,就放到队列中。补充一点,只要“&&”前面是true,无论“&&”后面是true还是false,结果都将返“&&”后面的值;只要“&&”前面是false,无论“&&”后面是true还是false,结果都将返“&&”前面的值。总结:假前真后!
  • for 循环的作用? 因为我们知道了每次存入数据后,queue中的长度,就相当于每一层节点的个数。拿本例子来说,第一次根节点为 3 ,queue 的 length为 1 。当存放当前层下一层的节点后,queue 里面就有了两个元素。那么下次再进行 while 循环的时候就能知道这一层有多少节点。

image-20221205204109924.png

107.二叉树的层次遍历II

题目链接:107. 二叉树的层序遍历 II

给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

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

思路:相对于102.二叉树的层序遍历,就是最后把result数组反转一下就可以了。

代码:根据上一题的代码,修改部分语句

 // 方法一:返回res的时候直接反转
 return res.reverse();
 ​
 // 方法二:在执行完for循环后,curLevel压入res时,从数组前头插入值,避免最后反转耽误更多时间
 res.unshift(curLevel);

199.二叉树的右视图

题目链接:199. 二叉树的右视图 - 力扣(LeetCode)

给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

思路我想的是在存入下一层的节点时,仅仅存右节点的。但是出现了问题。当测试用例为 [1,2] 时,期望输出 [1, 2] 。实际输出 [1]

问题就在于,题目不是想找右节点,而是从右边能看到的第一个节点。不一定限制左右子节点。

按照卡神的说法,“层序遍历的时候,判断是否遍历到单层的最后面的元素,如果是,就放进result数组中,随后返回result就可以了。”

代码

 var rightSideView = function (root) {
   let res = [], queue = [];
   queue.push(root);
   while (queue.length && root !== null) {
     // 记录当前层级节点个数
     let length = queue.length;
     while (length--) {
       let node = queue.shift();
       //length长度为0的时候表明到了层级最后一个节点
       if (!length) {
         res.push(node.val);
       }
       node.left && queue.push(node.left);
       node.right && queue.push(node.right);
     }
   }
   return res;
 };

所以,应该这样考虑:

  • 首先不需要在再定义一个 curLevel 了。
  • 不过还是需要设置一个length来记录节点的个数。
  • node 还是接住 queue 弹出来的数,那在这种不断while的过程中就能把一个个节点值放到queue里面
  • 当 queue 长度为 0 的时候,就说明到了这一层最后一个节点了,就是我们要求的值,压入 res 即可。

637.二叉树的层平均值

题目链接:637. 二叉树的层平均值 - 力扣(LeetCode)

给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。

输入:root = [3,9,20,null,null,15,7] 输出:[3.00000,14.50000,11.00000] 解释:第 0 层的平均值为 3,第 1 层的平均值为 14.5,第 2 层的平均值为 11 。 因此返回 [3, 14.5, 11]

思路:在层序遍历的时候把一层求个总和在取一个均值。

代码

 var averageOfLevels = function (root) {
   //层级平均值
   let res=[],queue=[];
   queue.push(root);
   while(queue.length&&root!==null){
       //每一层节点个数
       let length=queue.length;
       //sum记录每一层的和
       let sum=0;
       for(let i=0;i<length;i++){
           let node=queue.shift();
           sum+=node.val;
           node.left&&queue.push(node.left);
           node.right&&queue.push(node.right);
       }
       //每一层的平均值存入数组res
       res.push(sum/length);
   }
   return res;
 };

参考文章:

有些文章是在本地debug的时候遇到了一些问题,去查完相关文章以后,放在这里供后期复习。