199. 二叉树的右视图 (Medium)

专题归类: 05-二叉树 LeetCode 链接: https://leetcode.cn/problems/binary-tree-right-side-view/


在线做题: 写 Python 代码并运行 · Java 跳转 LeetCode

题目描述

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

示例 1:

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

示例 2:

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

示例 3:

输入:root = []
输出:[]

提示:

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

题目详细分析

  • 数据范围含义: 最多 100 个节点,非常小。任何算法都可以。
  • 输入输出特征: 输入根节点,输出一个列表,长度等于树的高度(每层贡献一个值)。
  • 边界条件: 空树返回 [];只有右子树时右视图就是前序遍历本身;只有左子树时右视图就是每层最右边的节点(可能在左边)。
  • 核心约束: 「右侧能看到」意味着每层只能看到最右边的那个节点。注意:最右边的节点不一定在右子树上——如果左子树比右子树深,左子树的下层节点可能成为右视图的一部分。
  • 隐藏条件: 这本质上是「每层最右节点」问题。也可以理解为按「根→右→左」的顺序 DFS,每层第一个访问到的节点。

小白版直白理解

就像你站在一棵大树的右边往左边看——每层你只能看到最靠右的那个节点,因为左边的节点都被右边的挡住了。如果某一层右子树没有节点而左子树有,你看到的就是左子树最靠右的那个节点。简单说就是:每层取最右边的节点。


解题思路

思路一:BFS 层序遍历(推荐)

核心思想: 对二叉树做层序遍历,每层取最后一个节点放入结果集。

为什么 BFS 适合? BFS 天然按层处理,在每层遍历时很容易知道当前节点是不是该层的最后一个(判断 i 是否等于 len(q)-1 或 level_size-1)。思路非常直观,不容易出错。

from collections import deque
 
def rightSideView(root):
    if not root:
        return []
 
    res = []
    q = deque([root])
 
    while q:
        level_size = len(q)
        for i in range(level_size):
            node = q.popleft()
            # 如果是当前层的最后一个节点,加入结果
            if i == level_size - 1:
                res.append(node.val)
            if node.left:
                q.append(node.left)
            if node.right:
                q.append(node.right)
 
    return res

思路二:DFS 反向先序遍历(根→右→左)

核心思想: 按照「根节点 → 右子树 → 左子树」的顺序进行 DFS。每层第一个访问到的节点就是该层最右边的节点。

为什么用这种顺序? 前序是「根→左→右」,而我们改成「根→右→左」。这样每层最先访问到的就是最右边的节点。用 depth == len(res) 判断是否是该层第一个被访问的节点——因为 DFS 优先走右边,所以每层第一个到达的节点就是右视图应该看到的。

def rightSideView(root):
    res = []
 
    def dfs(node, depth):
        if not node:
            return
        # 当前层还没有记录节点 → 当前节点是该层第一个访问到的(也是最右边的)
        if depth == len(res):
            res.append(node.val)
        # 先走右边(保证右边节点优先被访问)
        dfs(node.right, depth + 1)
        dfs(node.left, depth + 1)
 
    dfs(root, 0)
    return res

易错点

  • 右视图不只看右子树: 如果左子树比右子树深,底部的节点虽然在左子树但仍然能从右边看到(因为右子树没有挡住它)。所以不能只取右子树上的节点。
  • BFS 中 len(q) 必须固定: for i in range(len(q))len(q) 必须提前赋值给变量,否则会在循环中变化。
  • DFS 法的条件 depth == len(res) 只有首次到达某深度时才记录,后续再到达同一深度(从左子树来的)不记录。这个条件依赖 DFS 先走右子树的顺序。
  • 空树处理: 先判断 if not root: return []

框架提炼

BFS 每层取特定位置模板: 在层序遍历的基础上,可以在每层取出特定位置的节点(第一个、最后一个、第 k 个等)。

def level_extract(root):
    if not root:
        return []
    res = []
    q = deque([root])
    while q:
        for i in range(len(q)):
            node = q.popleft()
            if condition(i, len(q)):  # 根据位置条件选择节点
                res.append(node.val)
            if node.left: q.append(node.left)
            if node.right: q.append(node.right)
    return res

DFS 反向遍历模板: 当需要从某一侧观察树的节点时,调整 DFS 的访问顺序。

从右侧看:先右后左 (right → left)
从左侧看:先左后右 (left → right)

关联题目