面试经典算法21 - 二叉树的右视图
LeetCode.199
公众号:阿Q技术站
问题描述
给定一个二叉树的 根节点 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
思路
递归
- 递归遍历二叉树:从根节点开始,按照根右左的顺序递归遍历整棵二叉树。这样可以保证每一层最先访问到的节点是最右侧的节点。
- 记录每层最右侧节点的值:在遍历过程中,使用一个
map
或类似的数据结构来记录每一层最右侧节点的值。如果当前层级已经在map
中存在,则更新该层级的值为当前节点的值。 - 按层级顺序输出结果:最后,将
map
中按层级存储的节点值按顺序存入结果数组,并返回该数组作为最终的结果。
非递归
- 定义一个队列
queue
用于层序遍历二叉树,一个数组result
用于存储每层最右侧节点的值。 - 将根节点
root
入队。 - 在队列不为空的情况下,循环遍历每一层的节点:
- 记录当前队列的大小
size
,表示当前层级的节点数。 - 遍历当前层级的节点,如果是当前层级的最后一个节点,则将其值加入
result
数组中。 - 将当前节点的左右子节点入队。
- 记录当前队列的大小
- 返回
result
数组,其中存储了每层最右侧节点的值。
图解
- 定义一个队列
queue
用于层序遍历二叉树,一个数组result
用于存储每层最右侧节点的值。将根节点root
入队。
- 如果队列不为空,遍历当前层级的节点,获取队头,并将其弹出队列;如果是当前层级的最后一个元素,将其加入结果数组。当前层级遍历结束。
- 将当前节点的左右节点依次加入到队列中。
- 开始遍历当前层级在队列中的元素,获取队头的元素,弹出元素,并将当前节点的左右子节点入队。
- 继续遍历,如果是当前层级的最后一个元素,加入结果集。并将当前节点的左右子节点入队。当前层级结束。
- 遍历当前层级的元素,获取队头元素并弹出。
- 继续遍历当前层级,如果是最后一个节点,将其加入结果集中。
- 队列为空,退出循环。
参考代码
C++
递归
#include <iostream>
#include <vector>
#include <map>
#include <queue>
using namespace std;
// 二叉树节点的定义
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
void dfs(TreeNode* node, int level, map<int, int>& rightmost) {
if (!node) return; // 如果节点为空,直接返回
if (rightmost.find(level) == rightmost.end()) { // 如果当前层级不在map中,将当前节点的值存入map
rightmost[level] = node->val;
}
// 递归遍历右子树和左子树,层级加一
dfs(node->right, level + 1, rightmost);
dfs(node->left, level + 1, rightmost);
}
vector<int> rightSideView(TreeNode* root) {
vector<int> result; // 存储结果的数组
map<int, int> rightmost; // 存储每层最右侧节点值的map
dfs(root, 0, rightmost); // 调用递归函数开始遍历
// 将map中的节点值按层级顺序存入结果数组
for (auto& [level, val] : rightmost) {
result.push_back(val);
}
return result;
}
// 创建二叉树
TreeNode* createTree(vector<int>& nodes, int index) {
if (index >= nodes.size() || nodes[index] == -1) {
return nullptr; // 如果节点为空,则返回nullptr
}
TreeNode* root = new TreeNode(nodes[index]); // 创建当前节点
root->left = createTree(nodes, 2 * index + 1); // 创建左子树
root->right = createTree(nodes, 2 * index + 2); // 创建右子树
return root; // 返回当前节点
}
// 销毁二叉树
void destroyTree(TreeNode* root) {
if (!root) return; // 如果根节点为空,直接返回
destroyTree(root->left); // 递归销毁左子树
destroyTree(root->right); // 递归销毁右子树
delete root; // 删除当前节点
}
int main() {
vector<int> nodes = {1, 2, 3, -1, 5, -1, 4}; // 定义二叉树的层序遍历序列
TreeNode* root = createTree(nodes, 0); // 创建二叉树
vector<int> result = rightSideView(root); // 进行右视图遍历
for (int val : result) { // 输出遍历结果
cout << val << " ";
}
cout << endl;
destroyTree(root); // 销毁二叉树
return 0;
}
非递归
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
// 二叉树节点的定义
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
vector<int> rightSideView(TreeNode* root) {
vector<int> result; // 存储结果的数组
if (!root) {
return result; // 如果根节点为空,直接返回空数组
}
queue<TreeNode*> q; // 辅助队列,用于层级遍历
q.push(root); // 将根节点入队
while (!q.empty()) {
int level_size = q.size(); // 当前层级的节点数
for (int i = 0; i < level_size; ++i) {
TreeNode* node = q.front(); // 获取队头节点
q.pop(); // 弹出队头节点
// 如果是当前层级的最后一个节点,将其值加入结果数组
if (i == level_size - 1) {
result.push_back(node->val);
}
// 将当前节点的左右子节点入队
if (node->left) {
q.push(node->left);
}
if (node->right) {
q.push(node->right);
}
}
}
return result; // 返回结果数组
}
// 创建二叉树
TreeNode* createTree(vector<int>& nodes, int index) {
if (index >= nodes.size() || nodes[index] == -1) {
return nullptr; // 如果节点为空,则返回nullptr
}
TreeNode* root = new TreeNode(nodes[index]); // 创建当前节点
root->left = createTree(nodes, 2 * index + 1); // 创建左子树
root->right = createTree(nodes, 2 * index + 2); // 创建右子树
return root; // 返回当前节点
}
// 销毁二叉树
void destroyTree(TreeNode* root) {
if (!root) return; // 如果根节点为空,直接返回
destroyTree(root->left); // 递归销毁左子树
destroyTree(root->right); // 递归销毁右子树
delete root; // 删除当前节点
}
int main() {
vector<int> nodes = {1, 2, 3, -1, 5, -1, 4}; // 二叉树的层序遍历序列
TreeNode* root = createTree(nodes, 0); // 创建二叉树
vector<int> result = rightSideView(root); // 获取从右侧所能看到的节点值
for (int val : result) { // 输出结果
cout << val << " ";
}
cout << endl;
destroyTree(root); // 销毁二叉树
return 0;
}
Java
import java.util.*;
// 二叉树节点的定义
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
public class RightSideView {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> result = new ArrayList<>(); // 存储结果的列表
if (root == null) {
return result; // 如果根节点为空,直接返回空列表
}
Queue<TreeNode> queue = new LinkedList<>(); // 辅助队列,用于层级遍历
queue.add(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.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
}
}
return result; // 返回结果列表
}
// 创建二叉树
public TreeNode createTree(Integer[] nodes, int index) {
if (index >= nodes.length || nodes[index] == null) {
return null; // 如果节点为空,则返回null
}
TreeNode root = new TreeNode(nodes[index]); // 创建当前节点
root.left = createTree(nodes, 2 * index + 1); // 创建左子树
root.right = createTree(nodes, 2 * index + 2); // 创建右子树
return root; // 返回当前节点
}
// 销毁二叉树
public void destroyTree(TreeNode root) {
if (root == null) return; // 如果根节点为空,直接返回
destroyTree(root.left); // 递归销毁左子树
destroyTree(root.right); // 递归销毁右子树
}
public static void main(String[] args) {
Integer[] nodes = {1, 2, 3, null, 5, null, 4}; // 二叉树的层序遍历序列
RightSideView solution = new RightSideView();
TreeNode root = solution.createTree(nodes, 0); // 创建二叉树
List<Integer> result = solution.rightSideView(root); // 获取从右侧所能看到的节点值
for (int val : result) { // 输出结果
System.out.print(val + " ");
}
System.out.println();
solution.destroyTree(root); // 销毁二叉树
}
}
Python
from typing import List
from collections import deque
# 二叉树节点的定义
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def rightSideView(root: TreeNode) -> List[int]:
result = [] # 存储结果的列表
if not root:
return result # 如果根节点为空,直接返回空列表
queue = deque([root]) # 辅助队列,用于层级遍历
while queue:
level_size = len(queue) # 当前层级的节点数
for i in range(level_size):
node = queue.popleft() # 获取队头节点
# 如果是当前层级的最后一个节点,将其值加入结果列表
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 # 返回结果列表
# 创建二叉树
def createTree(nodes: List[int], index: int) -> TreeNode:
if index >= len(nodes) or nodes[index] is None:
return None # 如果节点为空,则返回None
root = TreeNode(nodes[index]) # 创建当前节点
root.left = createTree(nodes, 2 * index + 1) # 创建左子树
root.right = createTree(nodes, 2 * index + 2) # 创建右子树
return root # 返回当前节点
# 销毁二叉树
def destroyTree(root: TreeNode) -> None:
if not root:
return # 如果根节点为空,直接返回
destroyTree(root.left) # 递归销毁左子树
destroyTree(root.right) # 递归销毁右子树
# 测试代码
if __name__ == "__main__":
nodes = [1, 2, 3, None, 5, None, 4] # 二叉树的层序遍历序列
root = createTree(nodes, 0) # 创建二叉树
result = rightSideView(root) # 获取从右侧所能看到的节点值
print(result) # 输出结果
destroyTree(root) # 销毁二叉树