「前端刷题」199.二叉树的右视图(MEDIUM)

153 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第28天,点击查看活动详情

题目(Binary Tree Right Side View)

链接:https://leetcode-cn.com/problems/binary-tree-right-side-view
解决数:2224
通过率:65.6%
标签:树 深度优先搜索 广度优先搜索 二叉树 
相关公司:facebook bytedance amazon 

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

 

示例 1:

输入: [1,2,3,null,5,null,4]
输出: [1,3,4]

示例 2:

输入: [1,null,3]
输出: [1,3]

示例 3:

输入: []
输出: []

 

提示:

  • 二叉树的节点个数的范围是 [0,100]
  • -100 <= Node.val <= 100 

思路

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

翻译过来,就是:取每层节点中最右侧节点的值

关键点在于“最右侧”,看两个例子:

例一:二叉树[1, 2, 3, 4]的期望答案是[1, 3, 4]

显然:

  • 顶层(depth为0的一层)只有一个元素,val为1
  • 次成(depth为1的一层)有两个元素,节点2(左节点)和节点3(右节点),所以该层的val应该为3
  • 底层(depth为2的一层)只有一个元素,即节点4(左节点),所以该层的val应该为4

例二:二叉树[1, 2, 3, null,4]的期望答案是[1, 3, 4]

显然:

  • 顶层(depth为0的一层)只有一个元素,val为1
  • 次成(depth为1的一层)有两个元素,节点2(左节点)和节点3(右节点),所以该层的val应该为3
  • 底层(depth为2的一层)有两个元素,即空(左节点)和节点4(右节点),所以该层的val应该为4

虽然两棵树的答案都是[1, 3, 4]。但得到这个结果的原因是不一样的。

二叉树[1, 2, 3, 4]在depth为2的那层,没有右节点,所以该层的值是左节点的val。可以将该二叉树理解为[1, 2, 3, 4, null]

而二叉树[1, 2, 3, null, 4]在depth为2的那层,存在右节点,所以该层的左节点无论是不是null,该层都应取右节点的val。可以将该二叉树理解为[1, 2, 3, ?, 4]

逻辑梳理

明白了题意之后,逻辑就易于分析了。

层级遍历

很显然,常见树的层次遍历有DFSBFS两种方法。

最右侧节点的择取

由于BFS的本质是队列,所以可以保证,在每一次的遍历中,最右边的节点一定是该层的最后一个被遍历到的,所以本题采用BFS来解题,会容易理解一些。

答案数组的实现

首先,我们需要知道是哪一层,其次,无论该层的节点有多少,我们最终的都只是存取最右边的节点

满足这种形式的数据结构,非Map莫属了。

我们可以使用key来存放层次,用value来存放节点的val

并且因为使用的是BFS,所以可以保证每层的最右边节点一定是该层的最后一次读取,那么就意味着:该节点的val,一定会更新(覆盖)该层其他节点的val

不过,题意要求返回的是数组(Array),而现在我们使用的是Map,所以我们需在返回时进行进一步的变更。

答案数组存放的是按层次的val,最简单的方法就是遍历Map(map的遍历顺序由其key的添加顺序决定)取每个key的value。

在ES6中,已经有原生的API来实现该需求了,那就是Map.prototype.values(),想详细了解该API的同学可以查看MDN上的这篇文档

需要注意的是,该API返回的是一个可迭代对象(Iterator),所以需要再次利用ES6中的展开语法(...将其构造成数组,从而返回期待答案。

代码

以下是具体的代码实现,结合注释食用更佳~

var rightSideView = function(root) {
  if(!root) return [];

  // Map存储,key是当前节点的高度,value是当前节点的值
  let depthMap = new Map();

  // 构造队列,并赋予队首元素的初始高度
  let queue = [[root, 0]];

  while(queue.length) {
    // 取出队首元素
    let [ {val, left, right}, depth ] = queue.shift();

    /*
    关键点
    更新Map中每个key所对应的val,
    因为是BFS,所以可以保证最终Map的key所对应的val是同一层节点中的最右边节点的val
    */
    depthMap.set(depth, val);

    // 高度递增
    depth += 1;

    // 仅将存在的节点推入队列中
    if(left) {
      queue.push([left, depth]);
    }

    // 仅将存在的节点推入队列中
    if(right) {
      queue.push([right, depth]);
    }
  }
  
  // Map.prototype.values()返回是可迭代对象,故需利用“展开语法”来将其转换为数组
  return [...depthMap.values()]; 
}