给定一棵二叉树的根节点root,想象自己站在二叉树的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
示例:
输入:
root = [1,2,3,null,5,null,4]对应二叉树:
1 / \ 2 3 \ \ 5 4从右侧观察:
1 3 4输出:
[1,3,4]另一个例子:
输入:
root = [1,null,3]结构:
1 \ 3输出:
[1,3]二、为什么这道题值得学习?
这道题是二叉树遍历中的经典问题,也是面试高频题。
它主要考察:
- 二叉树层序遍历
- BFS 广度优先搜索
- 如何获取每一层指定位置的节点
很多同学看到“右视图”可能会想到:
从右边一直遍历。
但实际上:
二叉树右视图的本质是:
每一层中最右边的节点。
例如:
1 / \ 2 3 / \ 4 5按照层序遍历:
第一层:
1第二层:
2 3第三层:
4 5右视图看到的就是:
1 3 5所以:
只需要找到每一层最后访问的节点即可。
三、核心思想:层序遍历 + 记录每层最后一个节点
二叉树层序遍历:
也就是 BFS。
遍历顺序:
从上到下 从左到右例如:
1 / \ 2 3 / \ 4 5访问顺序:
1 2 3 4 5如果我们知道:
当前层有多少个节点。
那么:
这一层最后被访问的节点:
就是右视图看到的节点。
所以算法步骤:
- 使用队列保存节点
- 每次处理一层节点
- 记录当前层最后一个节点
- 加入结果数组
四、解题思路分析
1. 使用队列进行层序遍历
首先定义队列:
Queue<TreeNode>用于保存当前需要访问的节点。
初始化:
将根节点加入队列。
2. 获取当前层节点数量
每次进入循环:
记录当前层节点数量:
int size = queue.size();例如:
当前队列:
[2,3]说明:
这一层有两个节点。
3. 判断是否为当前层最后一个节点
遍历当前层:
for(int i = 0; i < size; i++)当:
i == size - 1说明:
当前节点是这一层最后访问的节点。
也就是:
右视图看到的节点。
加入答案:
result.add(node.val);五、代码实现(BFS层序遍历)
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; } }六、过程图解
例如:
1 / \ 2 3 \ \ 5 4要求:
右视图第一层
队列:
[1]数量:
size = 1访问:
1因为:
i = size - 1所以加入:
result = [1]加入下一层:
[2,3]第二层
队列:
[2,3]数量:
size = 2访问:
节点2:
i = 0不是最后一个。
访问:
节点3:
i = 1满足:
i == size - 1加入:
result = [1,3]第三层
队列:
[5,4]访问:
节点5:
不是最后。
访问:
节点4:
最后一个节点。
加入:
result = [1,3,4]最终答案:
[1,3,4]七、复杂度分析
时间复杂度:
O(N)原因:
每个节点都会被访问一次。
空间复杂度:
O(N)原因:
队列最多存储一层节点。
在最坏情况下:
完全二叉树最后一层节点数量接近:
N/2所以空间复杂度为:
O(N)八、另一种方法:DFS递归
除了 BFS。
也可以使用深度优先遍历。
核心思想:
优先访问右子树。
因为:
右边节点更可能出现在右视图中。
遍历顺序:
根节点 ↓ 右子树 ↓ 左子树例如:
1 / \ 2 3 \ 4访问:
1 3 4 2每个深度第一次访问到的节点:
就是该层右侧节点。
代码:
class Solution { List<Integer> result = new ArrayList<>(); public List<Integer> rightSideView(TreeNode root) { dfs(root,0); return result; } private void dfs(TreeNode root,int depth){ if(root == null){ return; } // 当前深度第一次访问 if(depth == result.size()){ result.add(root.val); } // 优先遍历右子树 dfs(root.right,depth + 1); // 再遍历左子树 dfs(root.left,depth + 1); } }九、两种方法比较
| 方法 | 思路 | 时间复杂度 | 空间复杂度 |
|---|---|---|---|
| BFS | 每层记录最后节点 | O(N) | O(N) |
| DFS | 优先访问右节点 | O(N) | O(H) |
面试中:
更加推荐:
✅ BFS层序遍历
因为它更加符合“右视图”的定义。
十、常见错误与避坑指南
❌ 错误一:只遍历右子树
很多人认为:
右视图就是一直走右孩子。
这是错误的。
例如:
1 / 2 \ 3如果只走右边:
只能得到:
1但是实际右视图:
1 2 3原因:
右视图看的是:
每层最右节点。
不是:
整棵树的右链。
❌ 错误二:记录每层第一个节点
错误:
i == 0这样得到的是:
左视图。
右视图应该:
记录:
i == size - 1❌ 错误三:忽略空树情况
如果:
root = null应该返回:
[]所以需要提前判断:
if(root == null)十一、面试高频追问
1. 为什么 BFS 可以解决右视图?
因为:
BFS 按层遍历。
而右视图要求:
每层最右节点。
所以:
记录每层最后访问节点即可。
2. 为什么 DFS 要先访问右子树?
因为:
右子树节点优先被访问。
每个深度第一次出现的节点:
就是该层最右节点。
3. 如果要求左视图怎么办?
只需要改变遍历顺序:
左视图:
记录每层第一个节点。
DFS:
优先访问左子树。
总结
LeetCode 199 的核心思想是:
二叉树右视图 = 每一层最右侧节点。
通过:
层序遍历 BFS控制每层节点数量:
遍历当前层 ↓ 记录最后一个节点 ↓ 加入答案这道题不仅考察二叉树遍历,
还帮助理解:
- BFS在树结构中的应用
- 如何处理二叉树层级信息
- 每层节点的统计技巧