二叉树右视图问题详解:BFS与DFS双解法全面解析
一、问题描述
给定一个二叉树的根节点 root
,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
示例1:
text
输入:root = [1,2,3,null,5,null,4] 输出:[1,3,4] 解释:1/ \2 3\ \5 4 从右侧看可以看到1, 3, 4
示例2:
text
输入:root = [1,2,3,4,null,null,null,5] 输出:[1,3,4,5] 解释:1/ \2 3/ 4 /5 从右侧看可以看到1, 3, 4, 5
二、问题分析
二叉树的右视图就是从右侧观察树时能看到的节点序列。经过分析可以发现:
-
每层最右边的节点构成右视图
-
需要按从上到下的顺序输出这些节点
-
空树返回空列表
三、BFS解法(层序遍历)
3.1 基本思路
使用广度优先搜索(BFS)进行层序遍历,记录每层最后一个节点。
3.2 代码实现
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 levelSize = queue.size();for (int i = 0; i < levelSize; i++) {TreeNode node = queue.poll();// 记录每层最后一个节点if (i == levelSize - 1) {result.add(node.val);}if (node.left != null) queue.offer(node.left);if (node.right != null) queue.offer(node.right);}}return result;} }
3.3 复杂度分析
-
时间复杂度:O(n),每个节点访问一次
-
空间复杂度:O(n),队列存储节点
3.4 优化版本
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 levelSize = queue.size();TreeNode lastNode = null;for (int i = 0; i < levelSize; i++) {lastNode = queue.poll();if (lastNode.left != null) queue.offer(lastNode.left);if (lastNode.right != null) queue.offer(lastNode.right);}if (lastNode != null) result.add(lastNode.val);}return result;} }
四、DFS解法(深度优先搜索)
4.1 基本思路
使用深度优先搜索(DFS),优先访问右子树,记录每层第一个访问到的节点。
4.2 代码实现
java
class Solution {public List<Integer> rightSideView(TreeNode root) {List<Integer> result = new ArrayList<>();dfs(root, 0, result);return result;}private void dfs(TreeNode node, int depth, List<Integer> result) {if (node == null) return;// 当深度等于结果列表大小时,说明是这一层第一个访问的节点if (depth == result.size()) {result.add(node.val);}// 先右后左,确保先访问右子树dfs(node.right, depth + 1, result);dfs(node.left, depth + 1, result);} }
4.3 复杂度分析
-
时间复杂度:O(n),每个节点访问一次
-
空间复杂度:O(h),递归栈空间,h为树高
五、两种解法的比较
特性 | BFS解法 | DFS解法 |
---|---|---|
实现方式 | 迭代+队列 | 递归/栈 |
空间复杂度 | O(n) | O(h) |
适用场景 | 树宽较大时 | 树深较大时 |
代码复杂度 | 中等 | 简单 |
访问顺序 | 按层访问 | 深度优先 |
六、边界情况测试
-
空树测试:
java
TreeNode root = null; assert rightSideView(root).isEmpty();
-
只有左子树:
java
// 1 // / // 2 TreeNode root = new TreeNode(1, new TreeNode(2), null); assert rightSideView(root).equals(Arrays.asList(1, 2));
-
只有右子树:
java
// 1 // \ // 2 TreeNode root = new TreeNode(1, null, new TreeNode(2)); assert rightSideView(root).equals(Arrays.asList(1, 2));
-
完全二叉树:
java
// 1 // / \ // 2 3 // / \ / \ // 4 5 6 7 TreeNode root = new TreeNode(1,new TreeNode(2, new TreeNode(4), new TreeNode(5)),new TreeNode(3, new TreeNode(6), new TreeNode(7))); assert rightSideView(root).equals(Arrays.asList(1, 3, 7));
七、常见问题解答
Q1:为什么DFS解法要先访问右子树?
A1:因为我们要找每层最右边的节点,先访问右子树可以确保每层第一个访问到的节点就是最右边的节点。
Q2:BFS解法中如何确定是每层最后一个节点?
A2:在层序遍历中,当处理到当前层的最后一个节点时(i == levelSize - 1),将其加入结果列表。
Q3:如何处理空树的情况?
A3:在函数开始时检查root是否为null,如果是直接返回空列表。
八、总结与扩展
本文详细讲解了二叉树右视图问题的两种解法:BFS和DFS。两种方法各有优缺点,适用于不同场景:
-
BFS更直观,适合处理层相关的问题
-
DFS代码更简洁,空间效率更高
扩展思考:
-
如何实现二叉树的左视图?(提示:修改访问顺序)
-
如何同时输出左右视图?
-
对于N叉树,如何实现右视图?
希望这篇文章能帮助你彻底理解二叉树右视图问题。如果有任何疑问或建议,欢迎在评论区留言讨论!