【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.hqwc.cn/news/195027.html

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

相关文章

开拓经验专栏:从十来天的晨型人体验开始

文章目录 拓新缘起契机实践心得 拓新 确定要新开一个板块&#xff0c;用来记录持续自我提升的经验和教训&#xff0c;着实遭遇了不少阻力。 首先&#xff0c;我的语文功底一向不行&#xff0c;当年高考前&#xff0c;语文分数在及格线上下跳动都是常事&#xff0c;现在却要通…

一文带你详细了解JVM运行时内存

一文带你详细了解JVM运行时内存 1. 程序计数器2. 虚拟机栈3. 本地方法栈4. 堆4.1 堆的总括4.1.1 概念4.1.2 特点4.1.3 设置堆内存大小4.1.4 堆的分类 4.2 新生代和老年代4.2.1 对象存储4.2.2 配置新生代和老年代的堆中占比 4.3 对象分配过程4.4 堆GC 5.元空间6.方法区6.1 方法区…

特效!视频里的特效在哪制作——Adobe After Effects

今天&#xff0c;我们来谈谈一款在Adobe系列中推出的一款图形视频处理软件&#xff0c;适用于从事设计和视频特技的机构&#xff0c;包括电视台、动画制作公司、个人后期制作工作室以及多媒体工作室的属于层类型后期软件——Adobe After Effects。 Adobe After Effects&#xf…

基于springboot实现校园在线拍卖系统项目【项目源码】计算机毕业设计

基于springboot实现校园在线拍卖系统演示 Javar技术 JavaScript是一种网络脚本语言&#xff0c;广泛运用于web应用开发&#xff0c;可以用来添加网页的格式动态效果&#xff0c;该语言不用进行预编译就直接运行&#xff0c;可以直接嵌入HTML语言中&#xff0c;写成js语言&…

一起Talk Android吧(第五百五十四回:分享一个Retorfit使用错误的案例)

文章目录 1. 案例场景2. 案例现象3. 原因分析和解决方案3.1 原因分析3.2 解决方案4. 经验总结各位看官们大家好,上一回中咱们说的例子是"解析Retrofit返回的数据",本章回中将分享一个 Retrofit使用错误的案例。闲话休提,言归正转,让我们一起Talk Android吧! 1. …

记录:RK3568显示异常。

最近调一个RK3568的新板子&#xff0c;板子其它接口功能都调试ok。可唯独在适配显示时发现&#xff0c;HDMI和MIPI显示均出现异常。当系统启动要进入桌面时候内核就开始报错。 因为这套源码之前在其它的板子上适配过&#xff0c;所以第一反应就是硬件问题或者是那个电压没配置…

Centos7 重置 Root 密码

Centos7 重置 Root 密码 1.启动服务器2.编辑启动项3.修改密码4.重新登陆 1.启动服务器 启动服务器后&#xff0c;不要直接进入系统&#xff0c;在开机页面按键盘【E】 2.编辑启动项 按【E】后进入如下页面&#xff0c;并按向下箭头&#xff0c;找到如图位置&#xff0c;添加如…

计算机毕业设计选题推荐-内蒙古旅游微信小程序/安卓APP-项目实战

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

Android修行手册-POI操作中文API文档

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

九、Linux用户管理

1.基本介绍 Linux系统是一个多用户多任务的操作系统&#xff0c;任何一个要使用系统资源的用户&#xff0c;都必须首先向系统管理员申请一个账号&#xff0c;让后以这个账号的身份进入系统 2.添加用户 基本语法 useradd 用户名 应用案例 案例1&#xff1a;添加一个用户 m…

深入流行推荐引擎3:Spotify音乐推荐系统

深入流行推荐引擎3&#xff1a;Spotify音乐推荐系统 Spotify音乐推荐系统通过矩阵分解发现每周&#xff08;Discover Weekly via Matrix Factorization&#xff09;Discover Weekly 如何运作&#xff1f;&#xff08;How Discover Weekly Works?&#xff09;矩阵分解&#xff…

2024年csdn最新最全的web自动化测试思路及实战

Page Objects 设计模式 Page Objects概念&#xff1a; Page Objects是指UI界面上用于与用户进行交互的对象 pageobjects 设计模式概念&#xff1a; pageobjects 模式是Selenium中的一种测试设计模式&#xff0c;主要是将每一个页面设计为一个Class&#xff0c;其中包含页面中…