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))(输出数组),在平衡树上非常节省。

相关推荐
Dlrb12118 小时前
C语言-指针三
c语言·算法·指针·const·命令行参数
Tisfy9 小时前
LeetCode 2540.最小公共值:双指针(O(m+n))
算法·leetcode·题解·双指针
IronMurphy9 小时前
【算法四十七】152. 乘积最大子数组
算法
REDcker9 小时前
有限状态机与状态模式详解 FSM建模Java状态模式与C++表驱动模板实践
java·c++·状态模式
basketball6169 小时前
C++ 构造函数完全指南:从入门到进阶
java·开发语言·c++
淘矿人10 小时前
Claude辅助DevOps实践
java·大数据·运维·人工智能·算法·bug·devops
Cosolar10 小时前
万字详解:RAG 向量索引算法与向量数据库架构及实战
数据库·人工智能·算法·数据库架构·milvus
想唱rap10 小时前
IO多路转接之poll
服务器·开发语言·数据库·c++
落羽的落羽11 小时前
【算法札记】练习 | Week4
linux·服务器·数据结构·c++·人工智能·算法·动态规划