LeetCode 199.二叉树的右视图

Algorithm

  • [🎯 问题(原题)](#🎯 问题(原题))
    • [🛠️ 解题思路(结论概述)](#🛠️ 解题思路(结论概述))
    • [📚 伪代码(右优先 DFS,递归)](#📚 伪代码(右优先 DFS,递归))
    • [🧾 C++ 实现(右优先 DFS,递归)](#🧾 C++ 实现(右优先 DFS,递归))
    • [🧠 正确性说明(为什么能得到"右侧视图")](#🧠 正确性说明(为什么能得到“右侧视图”))
    • [⏱️ 时间复杂度分析](#⏱️ 时间复杂度分析)
    • [📦 空间复杂度分析](#📦 空间复杂度分析)
    • [🔍 其他实现(层序遍历 BFS --- 备选)](#🔍 其他实现(层序遍历 BFS — 备选))
    • [✅ 总结(要点)](#✅ 总结(要点))

🎯 问题(原题)

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


🛠️ 解题思路(结论概述)

  • 🎯 目标:返回每一层从右侧能看到的第一个节点值(从上到下)。

  • ✅ 最优时间复杂度:O(n)(必须访问每个结点至少一次)。

  • ⚙️ 空间复杂度(最佳选择):

    • 推荐做法(先右子树的深度优先搜索)使用递归或显式栈:O(h)h 为树高(递归栈深度)。这是在平衡树上比宽度优先(BFS)更省空间的方案。
    • 宽度优先(BFS/层序遍历)会使用队列,最坏情况空间 O(n)(当最宽层包含 O(n) 节点时)。
  • 🧭 方案选择:优先采用 右优先的 DFS(深度优先) ------ 访问顺序为:当前 → 右 → 左。对每个深度只记录第一次访问到的节点值(即从右侧看到的节点)。该方法能保证时间 O(n),空间 O(h)。


📚 伪代码(右优先 DFS,递归)

plaintext 复制代码
function rightSideView(root):
    result = empty list
    dfs(node=root, depth=0, result)
    return result

function dfs(node, depth, result):
    if node is null:
        return
    if depth == length(result):
        append node.val to result    // first node seen at this depth (right-most)
    dfs(node.right, depth + 1, result)
    dfs(node.left,  depth + 1, result)

🧾 C++ 实现(右优先 DFS,递归)

cpp 复制代码
#include <vector>
using namespace std;

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x): val(x), left(nullptr), right(nullptr) {}
};

class Solution {
public:
    vector<int> rightSideView(TreeNode* root) {
        vector<int> result;
        dfs(root, 0, result);
        return result;
    }

private:
    void dfs(TreeNode* node, int depth, vector<int>& result) {
        if (!node) return;
        // If this is the first time we reach this depth, node is the rightmost for this depth
        if (depth == (int)result.size()) {
            result.push_back(node->val);
        }
        // Visit right first so the first node encountered at each depth is the rightmost
        dfs(node->right, depth + 1, result);
        dfs(node->left,  depth + 1, result);
    }
};

🧠 正确性说明(为什么能得到"右侧视图")

  • 在 DFS 中我们 先访问右子树 ,因此在每一层(depth)第一次被访问到的节点必然是该层最靠右的节点。我们用 depth == result.size() 判断该层是否已记录过节点:如果没记录(等于当前result长度),则当前节点是该深度的第一个(也即右侧看到的节点),把它加入结果。之后对左子树的访问不会覆盖该深度的记录。

⏱️ 时间复杂度分析

  • 每个节点最多被访问一次(入 dfs 并返回),因此时间复杂度为 O(n) ,其中 n 是节点总数。
  • 额外的开销为常数操作(比较、push 等),都被吞并进 O(n)。

📦 空间复杂度分析

  • 递归栈深度取决于树的高度 h

    • 最优/平均(平衡树)情况下:h = O(log n) → 空间 O(log n)(递归栈 + 结果数组)。
    • 最坏情况(退化为链表):h = O(n) → 空间 O(n)
  • 结果数组存储每层的一个节点:大小为层数,最坏为 O(n)(当每层只有一个节点的链表情况),但通常视为与输出规模一致。

  • 与 BFS(队列)相比:

    • BFS 时间同为 O(n)。
    • BFS 最坏空间是 O(n)(当某层很宽);而右优先 DFS 的空间是 O(h),在平衡树上明显优于 BFS。

🔍 其他实现(层序遍历 BFS --- 备选)

  • 思路:标准层序遍历(队列),每层遍历时记录该层最后被访问的节点值。
  • 时间:O(n);空间:最坏 O(n)(队列)。
  • 优点:直观;在某些场景(需要层信息)很方便。
  • 缺点:在高度受限的场景,空间可能比 DFS 大。

✅ 总结(要点)

  • 推荐实现:右优先 DFS(递归或显式栈),实现简单且一般能取得最优的辅助空间(O(h))。
  • 时间复杂度必然是 O(n)
  • 空间复杂度是 O(h) (递归栈) + O(min(h, n))(输出数组),在平衡树上非常节省。

相关推荐
Dream it possible!12 小时前
LeetCode 面试经典 150_二叉搜索树_二叉搜索树的最小绝对差(85_530_C++_简单)
c++·leetcode·面试
xxxxxxllllllshi12 小时前
【LeetCode Hot100----14-贪心算法(01-05),包含多种方法,详细思路与代码,让你一篇文章看懂所有!】
java·数据结构·算法·leetcode·贪心算法
前端小L12 小时前
图论专题(二十二):并查集的“逻辑审判”——判断「等式方程的可满足性」
算法·矩阵·深度优先·图论·宽度优先
铁手飞鹰12 小时前
二叉树(C语言,手撕)
c语言·数据结构·算法·二叉树·深度优先·广度优先
麦烤楽鸡翅13 小时前
简单迭代法求单根的近似值
java·c++·python·数据分析·c·数值分析
专业抄代码选手13 小时前
【Leetcode】1930. 长度为 3 的不同回文子序列
javascript·算法·面试
[J] 一坚14 小时前
深入浅出理解冒泡、插入排序和归并、快速排序递归调用过程
c语言·数据结构·算法·排序算法
czlczl2002092514 小时前
算法:二叉搜索树的最近公共祖先
算法
司铭鸿14 小时前
祖先关系的数学重构:从家谱到算法的思维跃迁
开发语言·数据结构·人工智能·算法·重构·c#·哈希算法
sulikey15 小时前
C++ 四十年:一段跨越时代的语言旅程
c++·c++40周年