# 199. 二叉树的右视图
# 题目描述
给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
示例 1:
输入: root = [1,2,3,null,5,null,4]
输出: [1,3,4]
2
示例 2:
输入: root = [1,null,3]
输出: [1,3]
2
示例 3:
输入: root = []
输出: []
2
提示:
- 二叉树的节点个数的范围是
[0,100] -100 <= Node.val <= 100
# 思路
什么是"从右侧看到的节点"?就是每一层最右边的那个节点。
想清楚这一点,本题就很简单了:用层序遍历,记录每一层的最后一个节点。
层序遍历用 BFS(广度优先搜索),借助队列实现:
- 根节点入队
- 每次处理一层的所有节点
- 记录该层的最后一个节点值
- 将下一层的节点入队
- 重复直到队列为空
关键点:怎么知道哪个是每层的最后一个节点?
在处理每一层之前,先记录当前队列的大小 size,这个 size 就是本层节点的数量。遍历完这 size 个节点,最后一个就是该层最右边的节点。
当然,也可以用深度优先搜索(DFS)解决,记录每个深度第一次访问的最右节点。但层序遍历的思路更直观。
# 模拟过程
以 root = [1,2,3,null,5,null,4] 为例:
1
/ \
2 3
\ \
5 4
2
3
4
5
初始化:
- 队列:[1]
- 结果:[]
第 1 层 (队列大小 = 1):
- 处理节点 1,它的左右孩子 2、3 入队
- 1 是本层最后一个,记录 1
- 队列:[2,3]
- 结果:[1]
第 2 层 (队列大小 = 2):
- 处理节点 2,它的右孩子 5 入队
- 处理节点 3,它的右孩子 4 入队
- 3 是本层最后一个,记录 3
- 队列:[5,4]
- 结果:[1,3]
第 3 层 (队列大小 = 2):
- 处理节点 5,无孩子
- 处理节点 4,无孩子
- 4 是本层最后一个,记录 4
- 队列:[]
- 结果:[1,3,4]
队列为空,遍历结束。
drawio 提示词: 画二叉树的层序遍历过程。第一张展示树结构 [1,2,3,null,5,null,4],从右侧看的视角用虚线或阴影表示,标注能看到的节点 1、3、4。第二张展示层序遍历的三个阶段,每个阶段画出队列状态、当前处理的层(高亮显示)、该层最右节点(用箭头或特殊颜色标注),并在下方列出结果数组的构建过程。两张图画布统一,Logo 放左下角。
文件名:
0199.binary-tree-right-side-view-01-visualization.drawio0199.binary-tree-right-side-view-02-level-traversal.drawio
# 解题代码
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> result;
if (root == nullptr) return result;
queue<TreeNode*> que;
que.push(root);
while (!que.empty()) {
int size = que.size(); // 当前层的节点数
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
if (i == size - 1) { // 本层最后一个节点
result.push_back(node->val);
}
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
}
return result;
}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 复杂度分析
- 时间复杂度:O(n),每个节点访问一次
- 空间复杂度:O(n),队列最多存储一层的节点,最坏情况(完全二叉树最底层)为 n/2
# 其他语言
# Python3
class Solution:
def rightSideView(self, root: Optional[TreeNode]) -> List[int]:
if not root:
return []
result = []
queue = deque([root])
while queue:
size = len(queue)
for i in range(size):
node = queue.popleft()
if i == size - 1: # 本层最后一个节点
result.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return result
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Java
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null) return result;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
if (i == size - 1) { // 本层最后一个节点
result.add(node.val);
}
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
}
return result;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Go
func rightSideView(root *TreeNode) []int {
result := []int{}
if root == nil {
return result
}
queue := []*TreeNode{root}
for len(queue) > 0 {
size := len(queue)
for i := 0; i < size; i++ {
node := queue[0]
queue = queue[1:]
if i == size - 1 { // 本层最后一个节点
result = append(result, node.Val)
}
if node.Left != nil {
queue = append(queue, node.Left)
}
if node.Right != nil {
queue = append(queue, node.Right)
}
}
}
return result
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# JavaScript
var rightSideView = function(root) {
if (!root) return [];
const result = [];
const queue = [root];
while (queue.length > 0) {
const size = queue.length;
for (let i = 0; i < size; i++) {
const node = queue.shift();
if (i === size - 1) { // 本层最后一个节点
result.push(node.val);
}
if (node.left) queue.push(node.left);
if (node.right) queue.push(node.right);
}
}
return result;
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 与代码随想录联系
这道题是层序遍历的经典应用。
我在代码随想录二叉树章节的 102. 二叉树的层序遍历 中详细讲解了层序遍历的模板代码。
层序遍历是二叉树题目中的重要工具,很多题目都可以用它解决:
- 找每层的最右/最左节点
- 找每层的最大/最小值
- 找某一层的节点
- 之字形遍历
建议录友们把层序遍历的模板代码掌握透彻,后面遇到类似题目就能直接套用。
另外,本题也可以用 DFS 解决,递归时传入深度参数,每个深度只记录第一次从右往左遍历到的节点。但层序遍历的思路更直观,代码也更清晰。
评论
验证登录状态...