【前端面试常见算法题系列】199. 二叉树的右视图(中等)

152 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情

一、题目描述

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

示例 1: image.png

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

示例 2:

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

示例 3:

输入: []
输出: []

提示:

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

二、思路分析

题目要求返回二叉树中每一层的最右边的节点,那么自然地想到一种思路:层序遍历二叉树,在遍历的过程中找到最右边的节点,将其压入答案数组就好了。而二叉树的层序遍历,其实也就是 BFS 。实现过程很简单,代码中有注释。

BFS 可以解题,那么猜想 DFS 是否也能做到。思路如下:递归遍历节点的右子树,如果该节点是当前层的最右的节点,则存进答案数组,不用再看左子树;否则递归遍历节点的左子树,如果是当前层的最右的节点,也可以存进答案数组。但这里有一个难点,就是怎么判断节点是最右的节点。

笔者一开始是想用变量标识的,即当该层的最右节点被找到后,则标识为 true ,那么下一次再遍历到当前层的时候,得知标识为 true ,说明当前层的最右节点已经被找到了,直接遍历下一层。但实践下来,发现行不通,无奈只能换一种方法。
其实判断当前节点是不是最右节点,可以用树的深度加以判断,这里难以描述,直接看注释吧,结合代码跑一下流程,就可以理解了,其实也不难。

三、AC 代码

二叉树构建:

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[]}
 */

BFS:

var rightSideView = function(root) {
    if (!root) return [];
    let arr = [];
    let que = [root];
    const bfs = () => {
        while (que.length > 0) {
            const len = que.length;
            let tmp = []; // 存储每一层的节点
            
            // 将 que 数组的节点搬到 tmp 数组中,并将 que 的值更新为下一层的节点
            for (let i = 0; i < len; i++) {
                const node = que.shift(); 
                tmp.push(node.val);
                // 注意:先压左子树,再压右子树
                if (node.left) {
                    que.push(node.left); // 存储下一层的节点
                }
                if (node.right) {
                    que.push(node.right);
                }
            }
            // 每一层的节点存储完毕,找到 tmp 数组的末尾元素就是每一层的最右节点
            arr.push(tmp[tmp.length - 1]);
            
            // while 循环,继续遍历下一层
        }
    }
    bfs();
    return arr;
};

DFS:

var rightSideView = function(root) {
    let arr = [];
    let depth = 0;
    const dfs = (node) => {
        if (!node) {
            return;
        }
        depth++;
        if (arr.length < depth) {
            // 这一层还没有记录值 
            // 说明 root 就是右侧视图的第一个节点
            arr.push(node.val);
        }
        // 注意:先递归右子树
        dfs(node.right);
        dfs(node.left);
        // 到底了,底下没有其他节点了,开始回溯
        depth--;
    }
    dfs(root);
    return arr;
};