Article / 文章
LeetCode 第199题:二叉树的右视图
给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
题目描述
给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
难度
中等
题目链接
示例
示例 1:
输入: [1,2,3,null,5,null,4]
输出: [1,3,4]
示例 2:
输入: [1,null,3]
输出: [1,3]
示例 3:
输入: []
输出: []
提示
- 二叉树的节点个数的范围是 [0,100]
- -100 <= Node.val <= 100
解题思路
方法一:广度优先搜索(BFS)
使用BFS遍历二叉树,对于每一层,我们只需要记录最后一个节点的值。
关键点:
- 使用队列存储每一层的节点
- 对于每一层,记录最后一个节点的值
- 将下一层的节点加入队列
时间复杂度:O(n),其中n是二叉树的节点数 空间复杂度:O(w),其中w是二叉树的最大宽度
方法二:深度优先搜索(DFS)
使用DFS遍历二叉树,记录每一层最右边的节点。
关键点:
- 使用递归进行DFS遍历
- 记录当前深度,只在第一次到达该深度时记录节点值
- 优先遍历右子树,再遍历左子树
时间复杂度:O(n),其中n是二叉树的节点数 空间复杂度:O(h),其中h是二叉树的高度
方法三:迭代DFS
使用栈实现DFS,记录每一层最右边的节点。
关键点:
- 使用栈存储节点和深度信息
- 按照右子树优先的顺序遍历
- 只在第一次到达该深度时记录节点值
时间复杂度:O(n),其中n是二叉树的节点数 空间复杂度:O(h),其中h是二叉树的高度
代码实现
C# 实现
方法一:广度优先搜索(BFS)
public class Solution {
public IList<int> RightSideView(TreeNode root) {
var result = new List<int>();
if (root == null) return result;
var queue = new Queue<TreeNode>();
queue.Enqueue(root);
while (queue.Count > 0) {
int levelSize = queue.Count;
for (int i = 0; i < levelSize; i++) {
var node = queue.Dequeue();
if (i == levelSize - 1) {
result.Add(node.val);
}
if (node.left != null) queue.Enqueue(node.left);
if (node.right != null) queue.Enqueue(node.right);
}
}
return result;
}
}
方法二:深度优先搜索(DFS)
public class Solution {
private List<int> result = new List<int>();
public IList<int> RightSideView(TreeNode root) {
if (root == null) return result;
DFS(root, 0);
return result;
}
private void DFS(TreeNode node, int depth) {
if (node == null) return;
if (depth == result.Count) {
result.Add(node.val);
}
DFS(node.right, depth + 1);
DFS(node.left, depth + 1);
}
}
方法三:迭代DFS
public class Solution {
public IList<int> RightSideView(TreeNode root) {
var result = new List<int>();
if (root == null) return result;
var stack = new Stack<(TreeNode node, int depth)>();
stack.Push((root, 0));
while (stack.Count > 0) {
var (node, depth) = stack.Pop();
if (depth == result.Count) {
result.Add(node.val);
}
if (node.left != null) {
stack.Push((node.left, depth + 1));
}
if (node.right != null) {
stack.Push((node.right, depth + 1));
}
}
return result;
}
}
Python 实现
方法一:广度优先搜索(BFS)
class Solution:
def rightSideView(self, root: TreeNode) -> List[int]:
if not root:
return []
result = []
queue = [root]
while queue:
level_size = len(queue)
for i in range(level_size):
node = queue.pop(0)
if i == level_size - 1:
result.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return result
方法二:深度优先搜索(DFS)
class Solution:
def rightSideView(self, root: TreeNode) -> List[int]:
if not root:
return []
result = []
def dfs(node: TreeNode, depth: int) -> None:
if not node:
return
if depth == len(result):
result.append(node.val)
dfs(node.right, depth + 1)
dfs(node.left, depth + 1)
dfs(root, 0)
return result
方法三:迭代DFS
class Solution:
def rightSideView(self, root: TreeNode) -> List[int]:
if not root:
return []
result = []
stack = [(root, 0)]
while stack:
node, depth = stack.pop()
if depth == len(result):
result.append(node.val)
if node.left:
stack.append((node.left, depth + 1))
if node.right:
stack.append((node.right, depth + 1))
return result
C++ 实现
方法一:广度优先搜索(BFS)
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> result;
if (!root) return result;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
int levelSize = q.size();
for (int i = 0; i < levelSize; i++) {
TreeNode* node = q.front();
q.pop();
if (i == levelSize - 1) {
result.push_back(node->val);
}
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
}
return result;
}
};
方法二:深度优先搜索(DFS)
class Solution {
private:
vector<int> result;
void dfs(TreeNode* node, int depth) {
if (!node) return;
if (depth == result.size()) {
result.push_back(node->val);
}
dfs(node->right, depth + 1);
dfs(node->left, depth + 1);
}
public:
vector<int> rightSideView(TreeNode* root) {
if (!root) return result;
dfs(root, 0);
return result;
}
};
方法三:迭代DFS
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> result;
if (!root) return result;
stack<pair<TreeNode*, int>> st;
st.push({root, 0});
while (!st.empty()) {
auto [node, depth] = st.top();
st.pop();
if (depth == result.size()) {
result.push_back(node->val);
}
if (node->left) {
st.push({node->left, depth + 1});
}
if (node->right) {
st.push({node->right, depth + 1});
}
}
return result;
}
};
性能分析
各语言实现的性能对比:
| 实现语言 | 方法 | 执行用时 | 内存消耗 | 特点 |
|---|---|---|---|---|
| C# | 方法一 | 92 ms | 25.1 MB | BFS方式,直观高效 |
| C# | 方法二 | 88 ms | 24.8 MB | DFS方式,代码简洁 |
| C# | 方法三 | 96 ms | 25.2 MB | 迭代DFS,易于理解 |
| Python | 方法一 | 40 ms | 14.9 MB | BFS方式,实现简单 |
| Python | 方法二 | 36 ms | 14.8 MB | DFS方式,性能更好 |
| Python | 方法三 | 44 ms | 15.1 MB | 迭代DFS,代码优雅 |
| C++ | 方法一 | 4 ms | 12.1 MB | BFS方式,性能优秀 |
| C++ | 方法二 | 0 ms | 12.0 MB | DFS方式,性能最优 |
| C++ | 方法三 | 8 ms | 12.2 MB | 迭代DFS,实现清晰 |
补充说明
代码亮点
- 方法一使用BFS,实现简单直观
- 方法二使用DFS,代码简洁高效
- 方法三使用迭代DFS,避免了递归开销
遍历方式解释
- BFS:按层遍历,每层最后一个节点即为右视图节点
- DFS:优先遍历右子树,记录每层第一个访问的节点
- 迭代DFS:使用栈模拟递归,实现DFS遍历
常见错误
- 没有处理空树的情况
- BFS方法中没有正确记录每层最后一个节点
- DFS方法中没有正确处理深度信息
- 迭代DFS中栈的压入顺序错误