二叉树优选算法(一)

一、根据二叉树创建字符串

题目介绍:

给你二叉树的根节点 root ,请你采用前序遍历的方式,将二叉树转化为一个由括号和整数组成的字符串,返回构造出的字符串。

空节点使用一对空括号对 "()" 表示,转化后需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。

f64c4cfac0024e5a8e90f1e107d52399.png

  • 树中节点的数目范围是 [1, 104]
  • -1000 <= Node.val <= 1000

思路:

这个题就是一个简单的开胃菜,思路就是在前序遍历的过程中先将所有子树都用括号括起来,最后看哪些括号可以省略,观察可以发现,如果左子树不为空,右子树为空,那么右子树括号就可以省略,如果左子树为空,右子树不为空,那左子树的括号不能省略,所以右子树存在就打印括号,不存在就不打印,而左子树存在则一定打印,如果为空的话就要看右子树是否存在

class Solution {
public:string tree2str(TreeNode* root) {string str;if (root == nullptr)return str;str += to_string(root->val);if (root->left||(root->left==nullptr&&root->right)) {str += '(';str+=tree2str(root->left);str += ')';}if (root->right) {str += '(';str+=tree2str(root->right);str += ')';}return str;}
};

二、二叉树的层序遍历

题目介绍:
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

5e51f3da9a724c7ca46eb3ddc01ea227.png

思路1:

对于层序遍历来说很简单,只需要利用一个队列即可,首先将根节点放入队列,在每次出一个节点时,就将这个节点的左右结点放入队列,直到队列为空就遍历完成了,但是这个题目要求我们将每一层的节点数据放到一个数组中,但是我们不知道队列中的每个数据是哪一层的,所以我们可以再创建一个队列,用于记录对应节点的层数

这里就需要两层循环,一层遍历每一层,一层遍历每一层的数据

class Solution {
public:vector<vector<int>> levelOrder(TreeNode* root) {vector<vector<int>> vv;queue<TreeNode*> q; // 保存结点queue<int> qlevel;  // 保存结点的层数int level = 1;if (root) {q.push(root);qlevel.push(level);}while (!q.empty()) {vector<int> v;while (level == qlevel.front()) {qlevel.pop();TreeNode* node = q.front();q.pop();v.push_back(node->val);if (node->left) {q.push(node->left);qlevel.push(level+1);}if (node->right) {q.push(node->right);qlevel.push(level+1);}}level++;vv.push_back(v);}return vv;}
};

思路2:

基于思路1进行优化,我们无非就是需要知道队列中的数据是对应哪一层的,如果我们知道每一层的数据个数,那就很容易控制队列,所以我们就在遍历完一层后,可以根据队列中的数据个数确定下一层的数据个数levelSize,因为上一层的数据都被出去了,而下一层的数据也都被放入队列了。

和上面一样这里也是两层循环

class Solution {
public:vector<vector<int>> levelOrder(TreeNode* root) {vector<vector<int>> vv;queue<TreeNode*> q;int leveSize=0;if (root) {q.push(root);leveSize = 1;}while (leveSize > 0) {vector<int> v;while (leveSize--) {TreeNode* node = q.front();v.push_back(node->val);q.pop();if (node->left) {q.push(node->left);}if (node->right) {q.push(node->right);}}leveSize = q.size();vv.push_back(v);}return vv;}
};

补充:

这里还有一个类似的引申题目

给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

dafa7a7694d044bfb4bbcdb8e379a586.png

与上述题目不同的是,他的要求是倒着遍历,那我们可以先正向遍历,最后将结果翻转一下

reverse(vv.begin(), vv.end());

三、二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

6e3ece98bef242b8921550ed94d5f1d5.png

思路1:

最近公共祖先有两种情况,如果一个节点1在另一个节点2的子树中,那节点2就是公共祖先。如果不是上述的情况,那这两个节点一定一个在公共祖先的左边,一个在右边。

对于一个节点来说,p和q和他的位置关系有三种

  • 一个在左一个在右(找到了)
  • 都在左(那公共节点一定在左边,往左边找)
  • 都在右(那公共节点一定在右边,往右边找)
class Solution {
public:bool IsChildTree(TreeNode* root, TreeNode* x) {if (root == nullptr)return false;if (root == x)return true;return IsChildTree(root->left, x) || IsChildTree(root->right, x);}TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {// 发现规律:这两个节点一定一个在最近的公共祖先的左边,一个在右边// 或者一个节点是另一个节点的子孙节点if (root == nullptr)return nullptr;if (root == p || root == q)return root;bool pInLeft,pInRight,qInLeft,qInRight;pInLeft=IsChildTree(root->left,p);pInRight=!pInLeft;qInLeft=IsChildTree(root->left,q);qInRight=!qInLeft;//一个在左一个在右if((pInLeft&&qInRight)||(pInRight&&qInLeft)){return root;}else if(pInLeft&&qInLeft)  //都在左边{return lowestCommonAncestor(root->left,p,q);}else     //都在右边{return lowestCommonAncestor(root->right,p,q);}}
};

但是上面的解法时间复杂度比较高,在最坏的情况下可以到达O(n^2),因为每次都需要判断两个节点是不是他的子树,如果这个两个节点在靠下的位置,每次判断都需要遍历查找到最下面

思路2:

如果我们有了两个节点到根节点的路径,那么这个题目就可以转变为链表相交的问题

所以重点就到了如何获取一个节点到跟节点的路径,我们可以利用栈,使用前序遍历这个树,碰到一个节点首先把它入栈,因为即使这个节点不是我们要找的节点,这个节点也可能是路径中的一个分支,然后继续遍历他的两个子树,如果他的两个子树都没找到,说明这个节点一定不属于路径中,就把这个节点弹出去。

当获取到两个节点到根节点的路径,首先让长的路径先走,直到两个链表的长度相同,在一块走,直到找到相交点

class Solution {
public:bool GetPath(TreeNode* root, TreeNode* x, stack<TreeNode*>& path) {if (root == nullptr)return false;// 前序遍历的思路,找x结点的路径// 遇到root结点先push⼊栈,因为root就算不是x,但是root可能是根->x路径中⼀个分⽀结点             path.push(root);if (root == x)return true;if (GetPath(root->left, x, path))return true;if (GetPath(root->right, x, path))return true;// 如果左右⼦树都没有x,那么说明上⾯⼊栈的root不是根->x路径中⼀个分⽀结点// 所以要pop出栈,回退,继续去其他分⽀路径进⾏查找path.pop();return false;}TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {stack<TreeNode*> pPath, qPath;GetPath(root, p, pPath);GetPath(root, q, qPath);// 模拟链表相交,两个路径找交点// ⻓的先⾛差距步,再⼀起⾛找交点while (pPath.size() != qPath.size()) {if (pPath.size() > qPath.size())pPath.pop();elseqPath.pop();}while (pPath.top() != qPath.top()) {pPath.pop();qPath.pop();}return pPath.top();}
};

 

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

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

相关文章

C++_关于异常处理throw-try-catch

文章目录 作用1. 无异常捕获2. 有异常捕获 作用 简单说&#xff0c;异常处理机制主要作用是让程序能够继续执行&#xff0c;或者以一种可控的方式终止&#xff0c;而非让程序因为错误直接崩溃 一个简单的动态数组类&#xff0c;来看看有异常捕获和无异常捕获的区别 1. 无异常…

如何使用 Python 实现多线程编程?

在Python中实现多线程编程&#xff0c;主要通过threading模块来完成。 这个模块提供了丰富的API用于创建和管理线程。多线程可以提高程序的响应性&#xff0c;并且对于I/O密集型任务&#xff08;如网络请求、文件读写等&#xff09;来说&#xff0c;可以显著减少等待时间。 由…

Java的封装、继承、多态

书接上文&#xff0c;我们聊完了Java的类和对象&#xff0c;有没有唤起你脑海的一些记忆呢&#xff0c;我们有了类和对象的基础之后&#xff0c;我们就可以衍生出来封装继承和多态。 封装 我理解一个东西&#xff0c;我一般会先想这个是什么&#xff0c;再是怎么用&#xff0…

【C#】新建窗体文件,Form、UserControl

从用途、功能性和架构方面进行描述。 1. 继承自 Form 的窗体&#xff08;通常是窗口&#xff09;&#xff1a; 在 C# 中&#xff0c;Form 是用于创建应用程序的主窗口或对话框窗口的类。当您继承自 Form 时&#xff0c;您创建的是一个完整的窗口&#xff0c;可以显示内容、与…

OSCP:我理解的Web环境知识

你需要特别关注以下模块所涵盖的知识点&#xff0c;因为它们在考试中出现的概率很高。 1、SQL 注入&#xff08;SQL Injection&#xff09; ●允许攻击者注入自定义的、潜在恶意的 SQL 代码&#xff0c;由底层数据库执行。 ●可能导致数据泄露或目标服务器上的远程代码执行&…

Java 转Scala的那些异同

引言 在这个数据爆炸的时代&#xff0c;大数据应用如雨后春笋般涌现。作为一名 Java 开发者&#xff0c;你可能会发现 Scala 这个新世界充满了诱惑。Scala 结合了面向对象和函数式编程的优点&#xff0c;尤其在大数据领域&#xff08;如 Apache Spark&#xff09;中表现得尤为…

Fiddler 5.21.0 使用指南:过滤浏览器HTTP(S)流量下(四)

概述 在上一篇文章中&#xff0c;我们介绍了一部分简单的过滤功能&#xff0c;已经可以帮助我们较为准确的定位到感兴趣的请求&#xff1b;提升我们的工作效率&#xff0c;我们可以通过设置更为复杂的过滤规则&#xff0c;精准到定位的我们想要的请求和响应信息。专注于分析对…

LabVIEW氢同位素单质气体定量分装系统

氢同位素单质气体在多个行业中有重要应用&#xff0c;如能源和化工。传统的分装方法面临精度和自动化程度不足的问题。为此&#xff0c;开发了一套基于LabVIEW和质量流量控制器的定量分装系统&#xff0c;提高分装精度和效率&#xff0c;同时减少资源浪费和环境污染。 项目背景…

包管理器npm,cnpm,yarn和pnpm

npm (Node Package Manager) 核心技术与工作原理 依赖解析&#xff1a; 广度优先搜索&#xff08;BFS&#xff09;&#xff1a;npm 使用 BFS 算法来解析依赖树&#xff0c;尽量扁平化 node_modules 目录以减少重复的依赖项。冲突处理&#xff1a;如果两个包需要同一个依赖的不…

各个系统查询电脑 CPU 核心数

Windows 方法 1: 使用任务管理器 右键点击任务栏&#xff0c;选择 任务管理器。在任务管理器中&#xff0c;点击 性能 标签。选择 CPU&#xff0c;在右侧会显示核心数&#xff08;“内核”&#xff09;和逻辑处理器数。 方法 2: 使用命令提示符 打开 命令提示符&#xff08;Win…

最新AI问答创作运营系统(SparkAi系统),GPT-4.0/GPT-4o多模态模型+联网搜索提问+问答分析+AI绘画+管理后台系统

目录 一、人工智能 系统介绍文档 二、功能模块介绍 系统快速体验 三、系统功能模块 3.1 AI全模型支持/插件系统 AI大模型 多模态模型文档分析 多模态识图理解能力 联网搜索回复总结 3.2 AI智能体应用 3.2.1 AI智能体/GPTs商店 3.2.2 AI智能体/GPTs工作台 3.2.3 自…

KNN_识别图片数字

1.实验过程省略灰度化处理过程&#xff0c;用已经处理好的txt数据进行训练 3.jpg from PIL import Image def imgtotxt(imgfile,txtfile,size (32,32)):image_file Image.open(imgfile).resize(size,Image.LANCZOS).convert(L)width,height image_file.sizef open(txtfile,…

外卖开发(六)—— 高查询量数据的缓存

外卖开发&#xff08;六&#xff09;—— 高查询量数据的缓存 一、代码实现缓存1、查询缓存2、修改数据时删除缓存 二、spring cache注解实现1、Cacaheable2、CacheEvict 一、代码实现缓存 1、查询缓存 在查询的时候&#xff0c;先去redis中查找数据&#xff0c;如果存在则直…

VAS1260Q奇力LED驱动芯片DCDC降压恒流

VAS1260Q是一款专为车规级LED照明设计的连续模式电感降压驱动器&#xff0c;能够高效地驱动单个或多个串联LED。它集成了高端输出电流检测电路&#xff0c;并通过外部电阻设置标称平均输出电流&#xff0c;具有高可靠性和宽广的应用场景。 核心技术参数 1. 输入…

移动端使用REM插件postcss之postcss-px2rem

目录 一、概念 二、核心特性 三、功能 四、插件模块 注意事项&#xff1a; 五、使用 安装&#xff1a; 配置 一、概念 工具类型&#xff1a;PostCSS是一个基于JavaScript的工具&#xff0c;用于转换CSS的工作流。核心理念&#xff1a;PostCSS的核心理念是“转换而非替…

渗透测试:网络安全的深度探索

一、引言 在当今数字化时代&#xff0c;网络安全问题日益凸显。企业和组织面临着来自各种恶意攻击者的威胁&#xff0c;他们试图窃取敏感信息、破坏系统或进行其他恶意活动。渗透测试作为一种主动的安全评估方法&#xff0c;能够帮助企业发现潜在的安全漏洞&#xff0c;提高网…

JS听到了强运的回响

正则表达式 介绍 正则表达式是用于匹配字符串中字符组合的模式&#xff0c;在JS中&#xff0c;正则表达式也是对象 通常用来查找&#xff0c;替换那些符合正则表达式的文本 就是筛选出符合条件的一类人 比如说 有人喜欢玩艾斯爱慕&#xff0c;那他喜欢的就是这一类人&…

文件的操作

什么是文件 如何是数据持久化——保存在硬盘上(文件&#xff0c;数据库)磁盘上的文件是文件在程序设计中&#xff0c;我们一般谈的文件有两种&#xff1a;程序文件、数据文件程序文件&#xff0c;比如源文件&#xff08;.c文件&#xff09;读a文件写到b文件里&#xff0c;此时a…

【18. 自定义类型:结构体类型】

文章目录 一、结构体类型的声明1.1 结构体回顾1.1.1 结构的声明1.1.2 结构体变量的创建和初始化 1.2 结构的特殊声明1.3 结构的⾃引⽤ 2. 结构体变量的创建和初始化2.1 对⻬规则2.2 为什么存在内存对⻬?2.3 修改默认对⻬数 3. 结构成员访问操作符3. 结构体传参 4. 结构体内存对…

疯狂原始人

With every sun comes a new day. 每每旭日东升 A new beginning. 都是崭新的开始 A hope that things will be better today than they were yesterday. 总是期冀今日之美远胜昨日 But not for me. My names Eep. 但不属于我 我叫小伊 And this is my family. The Crood…