【LeetCode】二叉树OJ

目录

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

二、二叉树的层序遍历

三、二叉树的层序遍历 II

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

五、二叉搜索树与双向链表

六、从前序与中序遍历序列构造二叉树

七、从中序与后序遍历序列构造二叉树


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

606. 根据二叉树创建字符串 - 力扣(LeetCode)

解题思路:本题在递归前序遍历二叉树的同时要注意()的省略,这时就有了三种情况:

  • 如果当前节点没有孩子,我们不需要在节点后面加上任何括号

  • 如果当前节点只有左孩子,我们在递归时,只需要在左孩子的结果外加上一层括号,而不需要给右孩子加上任何括号
  • 如果当前节点只有右孩子,我们在递归时,需要先加上一层空的括号 ‘()’ 表示左孩子为空,再对右孩子进行递归,并在结果外加上一层括号

解题代码: 

class Solution {
public:string tree2str(TreeNode* root) {if(root==nullptr)return "";string str=to_string(root->val);if(root->left||root->right)//有左孩子或者无左孩子有右孩子{str+="(";str+=tree2str(root->left);str+=")";}if(root->right)//有右孩子{str+="(";str+=tree2str(root->right);str+=")";}return str;}
};

二、二叉树的层序遍历

102. 二叉树的层序遍历 - 力扣(LeetCode)

解题思路:本题为了达到层序遍历,我们需要用到一个队列来保存每一层的节点,将将根节点入队列,每次出队列时都要将其孩子节点入队列:

还要有一个变量来记录每一层节点的个数,当该变量不为0时需要将节点出队列,所出节点都属于同一层的元素,每出一个节点将其减1。当该变量为0时,队列中都是上一层节点的孩子节点,所以都属于同一层节点,这时将变量置为队列中元素个数继续将节点出队列即可,直到队列为空

解题代码:

class Solution {
public:vector<vector<int>> levelOrder(TreeNode* root) {queue<TreeNode*> q;int levelsize=0;if(root)//根节点入队列{q.push(root);levelsize=1;}vector<vector<int>> vv;while(!q.empty()){vector<int> v;//记录每一层的数据while(levelsize--)//将上一层节点出队列的同时,将其孩子节点都入队列{TreeNode* front=q.front();q.pop();v.push_back(front->val);if(front->left)q.push(front->left);if(front->right)q.push(front->right);}vv.push_back(v);//将遍历完的一层数据存入levelsize=q.size();}return vv;}
};

三、二叉树的层序遍历 II

107. 二叉树的层序遍历 II - 力扣(LeetCode)

解题思路:该题是上题的变形题,很多同学容易在这题中想的过多,这一题想要的结果是上题的结果的逆置,所以按上题思路处理,最后将其结果逆置一下即可:

解题代码:

class Solution {
public:vector<vector<int>> levelOrderBottom(TreeNode* root) {queue<TreeNode*> q;int levelsize=0;if(root)//根节点入队列{q.push(root);levelsize=1;}vector<vector<int>> vv;while(!q.empty()){vector<int> v;//记录每一层的数据while(levelsize--)//将上一层节点出队列的同时,将其孩子节点都入队列{TreeNode* front=q.front();q.pop();v.push_back(front->val);if(front->left)q.push(front->left);if(front->right)q.push(front->right);}vv.push_back(v);//将遍历完的一层数据存入levelsize=q.size();}reverse(vv.begin(),vv.end());//将结果逆置return vv;}
};

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

236. 二叉树的最近公共祖先 - 力扣(LeetCode)

解题思路:对于该题我们需要了解两个节点最近公共祖先的特性,即这两个节点分别在最近公共祖先节点的左右子树;所以我们只要找到满足该条件的节点就找到了最近公共祖先节点

解题代码:

class Solution {
public:bool IsIntree(TreeNode* root, TreeNode* x){if(root==nullptr)return false;if(root==x)return true;return IsIntree(root->left,x)||IsIntree(root->right,x);}TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {if(root==p||root==q)return root;bool pInleft=IsIntree(root->left,p);bool pInright=!pInleft;bool qInleft=IsIntree(root->left,q);bool qInright=!qInleft;if((pInright&&qInleft)||(pInleft&&qInright)){return root;}else if(pInleft&&qInleft){return lowestCommonAncestor(root->left,p,q);}else{return lowestCommonAncestor(root->right,p,q);}}
};

但是该方法最坏情况下的时间复杂度为O(N^2),运行时长并不理想:

那下面我们换个思路来优化一下:我们可以记录从根节点到两个要查找节点的路径,从而将其转换为链表相交问题(对于链表的相交问题我们之前在LeetCode和牛客网经典链表题目合集 讲过),对于路径的存储我们可以用到栈来记录,最终找到共同的最近祖先节点:

class Solution {
public:bool GetPath(TreeNode* root, TreeNode* x,stack<TreeNode*>& s){if(root==nullptr)return false;s.push(root);if(root==x)return true;if(GetPath(root->left,x,s)||GetPath(root->right,x,s))return true;s.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();}
};

这样子时间复杂度就降到了O(N):

五、二叉搜索树与双向链表

二叉搜索树与双向链表_牛客题霸_牛客网 (nowcoder.com)

解题思路:在该题中需要利用二叉搜索树中序遍历的结果是升序的,所以我们在中序遍历时修改所在节点与前驱节点的指针指向即可;用cur指针表示当前节点,用prev指针表示中序遍历时当前节点的上一个遍历节点,使cur指针的左孩子:

下面是一个二叉搜索树中序遍历时,修改当前节点和前驱节点的指针指向的演示:

解题代码:

class Solution {
public:void InOrder(TreeNode* cur,TreeNode*& prev){if(cur==nullptr)return;InOrder(cur->left,prev);cur->left=prev;if(prev)prev->right=cur;//让前驱节点指针的右孩子指向当前节点prev=cur;//更新前驱节点指针位置InOrder(cur->right,prev);}TreeNode* Convert(TreeNode* pRootOfTree) {if(pRootOfTree==nullptr)return nullptr;TreeNode* prev=nullptr;InOrder(pRootOfTree,prev);//中序遍历的同时修改二叉树节点指针的指向TreeNode* head=pRootOfTree;//pRootOfTree并非链表的头节点,需要找到头节点后返回while(head->left){head=head->left;}return head;}
};

六、从前序与中序遍历序列构造二叉树

105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)

解题思路:

对于任意一颗树而言,前序遍历的形式总是

[ 根节点, [左子树的前序遍历结果], [右子树的前序遍历结果] ]

即根节点总是前序遍历中的第一个节点。而中序遍历的形式总是

[ [左子树的中序遍历结果], 根节点, [右子树的中序遍历结果] ]

只要我们在中序遍历中定位到根节点,那么我们就可以分别知道左子树和右子树中的节点数目。由于同一颗子树的前序遍历和中序遍历的长度显然是相同的,因此我们就可以对应到前序遍历的结果中,对上述形式中的所有左右括号进行定位

这样以来,我们就知道了左子树的前序遍历和中序遍历结果,以及右子树的前序遍历和中序遍历结果,我们就可以递归地对构造出左子树和右子树,再将这两颗子树接到根节点的左右位置

解题代码:

class Solution {
public:TreeNode* _buildTree(vector<int>& preorder, vector<int>& inorder,int begini,int endi,int& n) {if(begini>endi)return nullptr;TreeNode* newnode=new TreeNode(preorder[n]);//先利用先序遍历确定根节点int rooti=begini;while(rooti<=endi)//找到确定的根节点在中序遍历中的位置{if(inorder[rooti]==preorder[n])break;else++rooti;}++n;newnode->left=_buildTree(preorder,inorder,begini,rooti-1,n);//将剩下的左区间的节点连接到左子树上newnode->right=_buildTree(preorder,inorder,rooti+1,endi,n);//将剩下的右区间的节点连接到右子树上return newnode;}TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {int n=0;return _buildTree(preorder,inorder,0,preorder.size()-1,n);}
};

七、从中序与后序遍历序列构造二叉树

106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)

解题思路:该题和上一题是同类型题,我们使用后序遍历的逆序来确定根节点,再在中序遍历中找到其对应的节点,再递归地对构造出右子树和左子树(后序遍历的逆序是相当于先遍历右子树的前序遍历,所以我们先要构建右子树再构建左子树)

解题代码:

class Solution {
public:TreeNode* _buildTree(vector<int>& inorder,vector<int>& postorder,int begini,int endi,int& n) {if(begini>endi)return nullptr;TreeNode* newnode=new TreeNode(postorder[n]);//先利用后序遍历确定根节点int rooti=begini;while(rooti<=endi)//找到确定的根节点在中序遍历中的位置{if(inorder[rooti]==postorder[n])break;else++rooti;}--n;newnode->right=_buildTree(inorder,postorder,rooti+1,endi,n);//将剩下的右区间的节点连接到右子树上newnode->left=_buildTree(inorder,postorder,begini,rooti-1,n);//将剩下的左区间的节点连接到左子树上return newnode;}TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {int n=inorder.size()-1;return _buildTree(inorder,postorder,0,inorder.size()-1,n);}
};

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

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

相关文章

redis运维(八)数据类型(一)字符串

一 字符串 说明&#xff1a; 不需要精通,但是得有一个粗略的认识,然后利用help command查看具体使用仅做记录查询 ① 基础概念 说明&#xff1a; ex是用来收敛内存使用率备注&#xff1a; 早期set是不带ex的默认&#xff1a; 不设置ex,是常驻内存 key和value的命名规范 …

Java-类和类的关系

代码 总结&#xff1a; 【1】面向对象的思维&#xff1a;找参与者&#xff0c;找女孩类&#xff0c;找男孩类 【2】体会了什么叫方法的形参&#xff0c;什么叫方法的实参&#xff1a; 具体传入的内容 实参&#xff1a; 【3】类和类可以产生关系&#xff1a; &#xff08;1…

基于非洲秃鹫算法优化概率神经网络PNN的分类预测 - 附代码

基于非洲秃鹫算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于非洲秃鹫算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于非洲秃鹫优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

电容的耐压值是什么意思呢?

电容是什么&#xff1f; 电容是一种能以电荷的形式储存能量的装置。与同样大小的电池相比&#xff0c;电容能储存的能量要小得多&#xff0c;大约1w个电容存储的能量才顶一节电池存储的能量&#xff0c;但对于许多电路设计来说却足够使用了。 看下图的直插式电容&#xff0c;…

中级程序员——uniapp和小程序面试题

&#x1f604;博主&#xff1a;小猫娃来啦 &#x1f604;文章核心&#xff1a;uniapp和小程序面试题 文章目录 用uniapp有遇到一些兼容性问题吗&#xff1f;uniapp最大的优点是什么&#xff1f;uniapp如何实现多端兼容&#xff1f;uniapp是如何做跨端适配的&#xff1f;常用的u…

信息中心网络提出的背景、研究现状及研究内容

信息中心网络什么时候提出的&#xff1f;未来发展前景&#xff1f;有什么著名实验室在做&#xff1f; 1、提出背景&#xff1a; 互联网产生于上世纪60年代&#xff1a; &#xff08;1&#xff09;网络设备数量呈指数性增长 截至2022年底全球范围内预计将有超过280亿台终端设…

YOLO目标检测——无人机航拍输电线路绝缘瓷瓶数据集下载分享【对应voc、coco和yolo三种格式标签】

实际项目应用&#xff1a;电力系统运维、状态监测与故障诊断、智能电网建设等领域数据集说明&#xff1a;无人机航拍输电线路绝缘瓷瓶数据集&#xff0c;真实场景的高质量图片数据&#xff0c;数据场景丰富标签说明&#xff1a;使用lableimg标注软件标注&#xff0c;标注框质量…

【心得】基于flask的SSTI个人笔记

目录 计算PIN码 例题1 SSTI的引用链 例题2 SSTI利用条件&#xff1a; 渲染字符串可控&#xff0c;也就说模板的内容可控 我们通过模板 语法 {{ xxx }}相当于变相的执行了服务器上的python代码 利用render_template_string函数参数可控&#xff0c;或者部分可控 render_…

ThreadLocal优化

测试类证明一下ThreadLocal存储的数据是线程程安全的 package com.lin.springboot01;import org.junit.jupiter.api.Test;public class testThreadLocal {Testpublic void testThreadLocalSetAndGet(){//提供一个ThreadLocal对象ThreadLocal t1 new ThreadLocal();new Thread…

【SQL server】数据库、数据表的创建

创建数据库 --如果存在就删除 --所有的数据库都存在sys.databases当中 if exists(select * from sys.databases where name DBTEST)drop database DBTEST--创建数据库 else create database DBTEST on --数据文件 (nameDBTEST,--逻辑名称 字符串用单引号filenameD:\DATA\DBT…

Linux 基本语句_11_无名管道文件复制

父子进程&#xff1a; 父子进程的变量之间存在着读时共享&#xff0c;写时复制原则 无名管道&#xff1a; 无名管道仅能用于有亲缘关系的进程之间通信如父子进程 代码&#xff1a; #include <stdio.h> #include <unistd.h> #include <sys/types.h> #inc…

数据结构【DS】图的基本概念

定义 完全图(简单完全图) 完全无向图&#xff1a;边数为&#x1d427;&#x1d427;−&#x1d7cf;&#x1d7d0;完全有向图&#xff1a;边数为 &#x1d427;(&#x1d427;−&#x1d7cf;) 子图、生成子图 G的子图&#xff1a;所有的顶点和边都属于图G的图 G的生成子图…

数据结构与算法编程题4

删除线性表中值在s与t之间的元素&#xff08;s<t&#xff09;&#xff0c;s和t不合理或者顺序表为空则显示出错信息并退出运行。 #include <iostream> using namespace std;typedef int ElemType; #define Maxsize 100 #define OK 1 #define ERROR 0 typedef struct…

SIMULIA 2022 Abaqus新功能之非线性、工作流、子程序、Explicit等

Abaqus 非线性力学的功能增强 Valanis-Landel 超弹性材料 通过指定单轴试验数据和可选的体积试验数据&#xff08;v2022新增选项&#xff09;来定义Valanis-Landel 超弹性模型&#xff0c;该模型能精确地复现给定的数据&#xff0c;类似Marlow模型&#xff0c;但与Marlow模型的…

深信服AC设备用户认证

拓扑图 目录 拓扑图 一. 无需认证 思路&#xff1a;创建用户和组&#xff0c;将无需认证策略和用户绑定 1.创建组&#xff0c;组里添加用户 2. 新建不需要认证策略&#xff0c;将不需要认证策略和用户关联 3.验证 二.密码认证 思路&#xff1a;创建用户和组&#xff0c;并…

在Vue关于ue的computed属性中传递参数

computed的基本用法 computed是Vue实例中一个非常强大的计算属性&#xff0c;它的值主要根据依赖数据而变化。我们可以将一些简单的计算放在computed属性中&#xff0c;从而实现在模板中使用简单的表达式。 但是实际项目中通常有这么一个场景&#xff1a;根据传递不一样的参数值…

shell脚本学习笔记07

如何让shell实现 可选择性执行 的功能 用了while进行循环&#xff0c;是死循环&#xff0c;在循环时&#xff0c;使用case进行使用哪个脚本进行执行。使用clear进行每一次操作前的清屏&#xff0c;eof代表输入这个会显示目录。read用来读取输入的值&#xff0c;如果不输入值不会…

远程数据采集继电器RTU如何应用在智能电动汽车充电桩

远程数据采集继电器&#xff08;Remote Terminal Unit&#xff0c;RTU&#xff09;在智能电动汽车充电桩中的应用&#xff0c;可以为充电桩系统提供更高效、安全和可靠的远程监控与控制功能。下面将详细说明RTU在智能电动汽车充电桩中的应用。 远程监控功能&#xff1a; RTU可以…

IP地理位置定位技术:保护网络安全的新利器

随着互联网的普及和网络活动的日益频繁&#xff0c;网络安全问题越来越受到人们的关注。恶意流量攻击、网络欺诈等网络安全威胁层出不穷&#xff0c;如何准确识别和定位网络攻击者成为一项重要任务。在这个背景下&#xff0c;IP地理位置定位技术应运而生&#xff0c;为网络安全…

OpenHarmony Ohpm安装历程(个人踩坑,最后安装成功)

大家好&#xff0c;我是【八戒&#xff0c;你又涨价了哎】 以下是我个人在学习OpenHarmony过程中的分享&#xff0c;请大家多多指教 目录 问题描述&#xff1a; 尝试解决 尝试一、 尝试二、 尝试三、 最终解决方案 问题描述&#xff1a; 当我学习到使用OpenHarmony的三方…