面试经典算法系列之二叉数6 -- 二叉树的右视图

面试经典算法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

思路

递归
  1. 递归遍历二叉树:从根节点开始,按照根右左的顺序递归遍历整棵二叉树。这样可以保证每一层最先访问到的节点是最右侧的节点。
  2. 记录每层最右侧节点的值:在遍历过程中,使用一个 map 或类似的数据结构来记录每一层最右侧节点的值。如果当前层级已经在 map 中存在,则更新该层级的值为当前节点的值。
  3. 按层级顺序输出结果:最后,将 map 中按层级存储的节点值按顺序存入结果数组,并返回该数组作为最终的结果。
非递归
  1. 定义一个队列 queue 用于层序遍历二叉树,一个数组 result 用于存储每层最右侧节点的值。
  2. 将根节点 root 入队。
  3. 在队列不为空的情况下,循环遍历每一层的节点:
    • 记录当前队列的大小 size,表示当前层级的节点数。
    • 遍历当前层级的节点,如果是当前层级的最后一个节点,则将其值加入 result 数组中。
    • 将当前节点的左右子节点入队。
  4. 返回 result 数组,其中存储了每层最右侧节点的值。

图解

  1. 定义一个队列 queue 用于层序遍历二叉树,一个数组 result 用于存储每层最右侧节点的值。将根节点 root 入队。

  1. 如果队列不为空,遍历当前层级的节点,获取队头,并将其弹出队列;如果是当前层级的最后一个元素,将其加入结果数组。当前层级遍历结束。

  1. 将当前节点的左右节点依次加入到队列中。

  1. 开始遍历当前层级在队列中的元素,获取队头的元素,弹出元素,并将当前节点的左右子节点入队。

  1. 继续遍历,如果是当前层级的最后一个元素,加入结果集。并将当前节点的左右子节点入队。当前层级结束。

  1. 遍历当前层级的元素,获取队头元素并弹出。

  1. 继续遍历当前层级,如果是最后一个节点,将其加入结果集中。

  1. 队列为空,退出循环。

参考代码

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中,将当前节点的值存入maprightmost[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; // 存储每层最右侧节点值的mapdfs(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 = valself.left = leftself.right = rightdef 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 # 如果节点为空,则返回Noneroot = 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) # 销毁二叉树

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/619465.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数字乡村创新实践探索农业现代化与乡村振兴新路径:科技赋能农村全面振兴与农民幸福新篇章

随着信息技术的飞速发展&#xff0c;数字乡村成为推动农业现代化与乡村振兴的重要战略举措。科技赋能下的数字乡村创新实践&#xff0c;不仅提升了农业生产的智能化水平&#xff0c;也为乡村治理和农民生活带来了翻天覆地的变化。本文旨在探讨数字乡村创新实践在农业现代化与乡…

80% 的人都不会的 15 个 Linux 实用技巧

熟悉 Linux 系统的同学都知道&#xff0c;它高效主要体现在命令行。通过命令行&#xff0c;可以将很多简单的命令&#xff0c;通过自由的组合&#xff0c;得到非常强大的功能。 命令行也就意味着可以自动化&#xff0c;自动化会使你的工作更高效&#xff0c;释放很多手工操作&…

【周总结】

周总结 完成工单脚本的编写以及解决操作问题 完成相关 jira 问题修改 学习了 sentinel 整合项目使用流控&#xff0c;熔断&#xff0c;热点等功能的使用 2024/4/14 晴 1. 这周只办两件事&#xff0c;吃&#xff01;喝&#xff01;&#xff01;&#xff01; 2.忙忙忙&am…

978: 输出利用先序遍历创建的二叉树的中序遍历序列

解法&#xff1a; #include<iostream> #include<queue> using namespace std; // 定义二叉树结点 struct TreeNode {char val;TreeNode* left;TreeNode* right;TreeNode(char x) :val(x), left(NULL), right(NULL) {}; }; // 先序递归遍历建立二叉树 TreeNode* bu…

房贷还款(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h> # include <math.h>int main() {//初始化变量值&#xff1b;double m, r 0.01;float d 300000;float p 6000;//运算还款所需月份&#xff1b;m log10…

WPS二次开发系列:WPS SDk功能就概览

作者持续关注WPS二次开发专题系列&#xff0c;持续为大家带来更多有价值的WPS开发技术细节&#xff0c;如果能够帮助到您&#xff0c;请帮忙来个一键三连&#xff0c;更多问题请联系我&#xff08;QQ:250325397&#xff09; 作者通过深度测试使用了WPS SDK提供的Demo&#xff0…

便携式污水采样器的工作环境要求

便携式污水采样器的工作环境要求极为严格&#xff0c;以确保其能够准确、稳定地采集和分析水样。首先&#xff0c;该采样器必须在干燥、通风良好的环境中工作&#xff0c;以避免潮湿和高温对其内部电子元件的损害。同时&#xff0c;为了保证采样器的稳定性和精度&#xff0c;工…

水尺读数监测识别摄像机

水尺读数监测识别摄像机是一种具有巨大潜力的新型技术&#xff0c;它能够通过摄像头和智能识别算法&#xff0c;实时监测水尺的读数&#xff0c;并对水位进行准确识别。这种技术在水文监测、防洪减灾等领域有着广泛的应用前景。 在过去&#xff0c;水尺读数监测通常需要人工观测…

行业大佬为什么要用海外仓系统?位像素海外仓系统有什么优势?

在全球化浪潮下&#xff0c;跨境电商蓬勃发展&#xff0c;各路大佬企业纷纷崭露头角。而在跨境电商这个竞争激烈的市场中&#xff0c;为何众多行业大佬会选择使用海外仓系统呢&#xff1f;这背后的原因并不复杂&#xff0c;但足以让每一个追求效率和效益的企业家心动。让我们看…

(四)qt中使用ffmpeg播放视频,可暂停恢复

一、在qt中添加ffmpeg库及头文件 INCLUDEPATH /usr/local/ffmpeg/include LIBS -L/usr/local/lib -lavutil -lavcodec -lavformat -lswscale 二、详细代码 FFempegVideoDecode 视频解码类&#xff08;放入线程中&#xff09; ffmpegvideodecode.h #ifndef FFMPEGVIDEODE…

攻防世界06-get_post

http的两种请求方式是get和post&#xff0c;比如我用通过通过这两种方式传参&#xff0c;分别传a1和b2。get的请求方式是通过在网址后面加上“&#xff1f;a1&b2”,例如&#xff1a;https://adworld.xctf.org.cn/task/answer?a1&b2 post传参的话通过hackbar&#xff0…

可视化大屏没有了动效,那真是缺少了精气神。

动效在可视化大屏中有以下几个作用&#xff1a; 强调关键信息 通过动效&#xff0c;可以将关键信息以醒目的方式呈现在大屏上&#xff0c;吸引用户的注意力。例如&#xff0c;可以使用动画效果突出显示重要的数据点或指标&#xff0c;帮助用户更快速地理解和获取关键信息。 增…