给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
示例 1:
**输入:**root = [1,2,3,null,5,null,4]
输出:[1,3,4]
示例 2:
**输入:**root = [1,2,3,4,null,null,null,5]
输出:[1,3,4,5]
示例 3:
**输入:**root = [1,null,3]
输出:[1,3]
示例 4:
**输入:**root = []
输出:[]
提示:
- 二叉树的节点个数的范围是
[0,100] -100 <= Node.val <= 100
1. 算法核心思想:层序遍历的“降维打击”
题目要求“从右侧所能看到的节点值”。如果我们试图用人脑去想象遮挡关系,会觉得非常复杂(因为左子树如果有特别长的分支,也会从右边露出来)。
但是,如果我们把它转换成“层序遍历”的问题,思路瞬间降维: 所谓的“右视图”,本质上就是二叉树每一层里的“最后一个节点”!
只要我们能够老老实实地把这棵树一层一层地剥开,然后把每一层遍历到最后的那个元素塞进结果数组里,这道题就迎刃而解了。
2. 代码逻辑拆解
- 万能模板复用:继承了标准层序遍历的精髓。利用
count变量提前锁死了当前层的人数,这使得我们可以放心地在一个for循环里把当前层的人全部请出队列,同时把下一层的人排进队列。 - 点金之笔
if (i == count - 1): 在当前层的for循环中,i的范围是从0到count - 1。 当i走到count - 1时,说明当前出队的node就是这一层的最后一名排队者(也就是最靠右的那个节点)。把它抓进result数组里,完美符合“右视图”的定义。
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> result;
// 1. 边界拦截:如果树为空,直接返回空数组
if (root == NULL) {
return result;
}
queue<TreeNode*> q;
q.push(root);
int count = 1; // 记录当前层的节点数
// 2. 开始水波纹扩散(层序遍历)
while (!q.empty()) {
// 3. 遍历当前层的所有节点
for (int i = 0; i < count; i++) {
TreeNode* node = q.front();
q.pop();
// 将下一层的节点(左右孩子)排入队列
if (node->left != NULL) {
q.push(node->left);
}
if (node->right != NULL) {
q.push(node->right);
}
// 4. 核心点金之笔:捕捉最右侧的节点
// 当 i 等于当前层总数减 1 时,说明这是当前层的最后一个节点
if (i == count - 1) {
result.push_back(node->val);
}
}
// 5. 当前层全部出队,队列里剩下的全都是下一层的新节点,更新 count
count = q.size();
}
return result;
}
};
3. 复杂度分析
- 时间复杂度:O(N)。其中 N 是二叉树的节点数。无论是哪一层,树上的每一个节点都会被精确地进队一次、出队一次,整体时间开销与节点数量成正比。
- 空间复杂度:O(N)。空间消耗主要在于队列
q。在最坏情况下(例如一棵完美的满二叉树的最后一层),队列中最多会同时存放大约 N/2 个节点,所以空间复杂度为线性的 O(N)。
