C++二叉树常见OJ题分析

article/2025/6/17 23:57:09

OJ(一):根据二叉树创建字符串

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

 1.(ps:接下来的解答来自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;}
};

OJ(二):二叉树的最近公共祖先

情况一:它们其中一个是根节点,就直接返回根。

情况二:

根据上面我们图知:如果一个在左树,一个在右树,那么当前根就是它们最近的公共祖先。

解释:

1.我们要写一个find函数,用来找它们是符合哪种情况:即找它们是在那支树里

若一个在左树,一个在右树,直接返回它们的当前根

若两个都在当前树的同一支树,则继续去递归,进去下一个更近的树。

2.所以我们可以定义四个变量:即代码中的pInLeft,pInRight,qInLeft,qInRight,返回类型是bool

其中,按照上面的变量名,到下面,你就会很清晰地看到它的优势。

class Solution {
public:bool Find(TreeNode*tree,TreeNode* x){if(tree==nullptr)return false;return tree==x||Find(tree->left,x)||Find(tree->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=Find(root->left,p);//这里就直接逻辑取反即可,因为p不是左就是右pInRight=!pInLeft;qInLeft=Find(root->left,q);//这里就直接逻辑取反即可,因为q不是左就是右qInRight=!qInLeft;//如果都在左边if(pInLeft &&qInLeft){return lowestCommonAncestor(root->left,p,q);}//都在右边else if(pInRight &&qInRight){return lowestCommonAncestor(root->right,p,q);}return root;}
};

法二:利用栈去完成。

1.建立两个栈,分别把它们经过遍历的值都push进去各自的栈中,知道找到它们的值为止。

接着,如果它们栈的长度不一样的话,先pop掉长的那个栈,令它们的长度相等,再去比较

比较时,如果它们两个的栈顶值不一样时,就pop掉,反之,它们两个栈顶的值相等时,即找到了它们的最近公共祖先了。

class Solution {
public://找路径的函数bool Findpath(TreeNode*root,TreeNode*x,stack<TreeNode*>& path){if(root==nullptr)return false;path.push(root);if(root==x){return true;}//如果不为空,说明找到了if(Findpath(root->left,x,path)){return true;}  if(Findpath(root->right,x,path)){return true;}//如果到最后都找不到,所以没有,就需要pop掉一开始的值path.pop();return false;}TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {stack<TreeNode*>ppath,qpath;Findpath(root,p,ppath);Findpath(root,q,qpath);while(ppath.size()>qpath.size()){ppath.pop();}while(ppath.size()<qpath.size()){qpath.pop();}while(ppath.top()!=qpath.top()){qpath.pop();ppath.pop();}return ppath.top();}
};

OJ(三):二叉树的分层遍历

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

层序遍历:一层一层地遍历

1.这里使用到了队列来借助完成

2.开始时先入它的根,接着进入循环(条件是:队列不为空)

记录下队列的头结点,再从队列里删去。接着再从已经记录的头节点,去看它的左子树和右子树为不为空,不为空的话,就push进去队列(记得按照左->的顺序入队列)

 把每一层的值放进去vector<int>后,再统一把这一层的值push进去ret中。

class Solution {
public:vector<vector<int>> levelOrder(TreeNode* root) {vector<vector<int>> ret;//注意这里放的是它的结点,所以类型不要弄成int了queue<TreeNode*> q;if(root)q.push(root);while(!q.empty()){vector<int >ans;int size=q.size();for(int i=1;i<=size;i++){//这里也是注意是结点,而不是intTreeNode*cur=q.front();q.pop();ans.push_back(cur->val);if(cur->left){q.push(cur->left);}if(cur->right){q.push(cur->right);}} ret.push_back(ans);}return ret;}
};

OJ(四):二叉树的层序遍历2

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

这里跟上面的一样的,只是这道题的最后需要你逆置一下即可

多了一行与上一题:reverse(vv.begin(),vv.end());
class Solution {
public:vector<vector<int>> levelOrderBottom(TreeNode* root) {vector<vector<int>> vv;queue<TreeNode*>q;if(root)q.push(root);while(!q.empty()){vector<int> v;int size=q.size();for(int i=0;i<size;i++){TreeNode*cur=q.front();q.pop();v.push_back(cur->val);if(cur->left)q.push(cur->left);if(cur->right)q.push(cur->right);}vv.push_back(v);}reverse(vv.begin(),vv.end());return vv;}
};

OJ(四):二叉搜索树与双向链表

 二叉搜索树与双向链表_牛客题霸_牛客网

left:中序上一个

right:中序下一个 

画递归图:就可以更加直观了,这里就并不画了。 

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) {TreeNode*prev=nullptr;Inorder(pRootOfTree,prev);TreeNode*head=pRootOfTree;while(head &&head->left){head=head->left;}return head;}
};

OJ(五):从前序与中序遍历序列构造二叉树 

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

 1.

注意:previ加&

class Solution {
public:TreeNode* _buildTree(vector<int>& preorder, vector<int>& inorder,int& previ,int inbegin,int inend){if(inbegin>inend)return nullptr;TreeNode*root=new TreeNode(preorder[previ]);int rooti=inbegin;//找根在中序的那个位置while(rooti<inend){if(preorder[previ]==inorder[rooti])break;rooti++;}previ++;root->left=_buildTree(preorder,inorder,previ,inbegin,rooti-1);root->right=_buildTree(preorder,inorder,previ,rooti+1,inend);return root;}TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {int i=0;TreeNode*root=_buildTree(preorder,inorder,i,0,inorder.size()-1);return root;}
};

OJ(六):从中序与后序遍历序列构造二叉树 

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

 这道题跟上面那道题差不多相似的。

因为我们想想:

后序:左右根       前序:根左右

那么,它们的区别不过只是,后序的根在最后,前序的根在开始而已。并且后序的顺序是从右子树到左子树,前序的顺序是从左子树到右子树。

class Solution {
public:TreeNode* _buildTree(vector<int>& inorder, vector<int>& postorder,int& posti,int inbegin,int inend){if(inbegin>inend)return nullptr;TreeNode*root=new TreeNode(postorder[posti]);int rooti=inbegin;while(rooti<inend){if(postorder[posti]==inorder[rooti])break;rooti++;}posti--;//先右再左root->right=_buildTree(inorder,postorder,posti,rooti+1,inend);root->left=_buildTree(inorder,postorder,posti,inbegin,rooti-1);return root;} TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {//最后一个下标int i=postorder.size()-1;TreeNode*root=_buildTree(inorder,postorder,i,0,inorder.size()-1);return root;}
};

 OJ(七):二叉树的前序遍历(非递归)

 1.利用栈来完成:

class Solution {
public:vector<int> preorderTraversal(TreeNode* root) {stack<TreeNode*>st;vector<int> v;TreeNode*cur=root;while(cur || !st.empty()){while(cur){v.push_back(cur->val);st.push(cur);cur=cur->left;}TreeNode*front=st.top();st.pop();cur=front->right;}return v;}
};

OJ(八):二叉树的中序遍历 (非递归)

94. 二叉树的中序遍历 - 力扣(LeetCode)

这个跟前序差不多很相似:

class Solution {
public:vector<int> inorderTraversal(TreeNode* root) {stack<TreeNode*>st;vector<int> v;TreeNode*cur=root;while(cur||!st.empty()){while(cur){st.push(cur);cur=cur->left;}TreeNode*front=st.top();st.pop();v.push_back(front->val);cur=front->right;}return v;}
};

OJ(九):二叉树的后序遍历(非递归)

145. 二叉树的后序遍历 - 力扣(LeetCode)

这里与前面两道有所差异:

这里后序遍历时:使用到了prev来记录前一个结点

class Solution {
public:vector<int> postorderTraversal(TreeNode* root) {stack<TreeNode*>st;vector<int>v;TreeNode*cur=root;TreeNode*prev=nullptr;while(cur ||!st.empty()){//左树while(cur){st.push(cur);cur=cur->left;}TreeNode*front=st.top();//因为上面循环中已经知道了cur为空了,即说明左子树已经空了,//左右只需要看它的右子树是否空,如果为空,所以这个是最左边的数了,//就可以进行插入v了,而且第二个是防止它本身就在右子树的,已经遍历完的情况if(front->right==nullptr ||front->right==prev){v.push_back(front->val);prev=front;st.pop();}elsecur=front->right;}return v;}
};

好了,关于二叉树的OJ题分析就到此结束了,希望大家都有所收获!

最后,到了本次鸡汤环节:

图片文字与大家共勉!


http://www.hkcw.cn/article/lrhgkTuGvO.shtml

相关文章

Spring Boot养老院管理系统源码分享

概述 基于Spring Boot开发的养老院管理系统&#xff0c;该系统通过智能化管理模块&#xff0c;为养老机构提供高效运营解决方案。 主要内容 后台管理功能 系统后台功能完善&#xff0c;左侧导航栏涵盖首页、安全巡查管理、设备管理等模块。设备管理界面以表格形式清晰展示设…

数据库-MySQL索引事务

1 索引 针对查询操作引入的优化手段 可以通过索引加快查询的速度 避免针对表遍历 索引缺点&#xff1a; 1.占用更多空间&#xff0c;生成索引需要一系列数据结构 一系列额外数据 2.可能会降低插入修改删除的速度 ps.如果这个表本来就很大&#xff0c;创建索引容易把数据库服务…

leetcode hot100刷题日记——32.杨辉三角

class Solution { public:vector<vector<int>> generate(int numRows) {//感觉是不是就是找规律遍历啊//i层共有i1个数字//i层的0和i位置都是1//i层的其他位置j的数字i-1层j-1位置i-1层j位置//注意二维vector数组的初始化vector<vector<int>>res(numRo…

数据中台(大数据平台)之元数据管理

元数据管理是数据管理的基础&#xff0c;数据中台产品要能够提供各类元数据采集的适配器&#xff0c;自动化采集技术元数据&#xff0c;并在技术元数据的基础上补充管理属性和业务属性&#xff0c;为后续的数据资源目录、数据安全管控、报表开发提供统一的口径。并能够在数据集…

TDenigne 集群可视化管理

可视化管理工具 为方便用户更高效地使用和管理 TDengine&#xff0c;TDengine 3.0 版本推出了一个全新的可视化组件 taosExplorer。这个组件旨在帮助用户在不熟悉 SQL 的情况下&#xff0c;也能轻松管理 TDengine 集群。通过 taosExplorer&#xff0c;用户可以轻松查看 TDengi…

【Linux 学习计划】-- 进程地址空间

目录 进程地址的引入 进程地址空间基础原理 区域划分的本质 如何理解进程地址空间 越界访问的本质 进一步理解写时拷贝 重谈 fork 返回值 结语 进程地址的引入 我们先来看一段代码&#xff1a; 首先我们可以看到&#xff0c;父进程和子进程是可以同时可以看到一个变量…

foundationpose位姿检测环境搭建与数据集制作

foundationpose环境搭建数据集制作 注&#xff1a;本教程为在未知明确方法的探索步骤记录&#xff0c;由于时间原因未做整理&#xff0c;可能有不必要步骤&#xff0c;建议先看完整篇文章理清思路在动手制作 创建数据集 保存RGB和Depth图像: 使用data_collect.py脚本来保存R…

某乎x-zse-96 破解(补环境版本)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、总体概述二、请求分析分析请求流程三、逆向分析总结一、总体概述 本文主要实现某乎x-zse-96 破解(补环境版本),相关的链接: https://www.zhihu.com/search?type=content&q=%25E7%258…

智慧物流园区整体解决方案

该智慧物流园区整体解决方案借助云计算、物联网、ICT 等技术,从咨询规划阶段介入,整合供应链上下游资源,实现物流自动化、信息化与智能化。方案涵盖智慧仓储管理(如自动化立体仓储系统、温湿度监控)、智慧物流(运输管理系统 TMS、GPS 监控)、智慧车辆管理(定位、调度、…

车载诊断架构SOVD --- 车辆发现与建连

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 钝感力的“钝”,不是木讷、迟钝,而是直面困境的韧劲和耐力,是面对外界噪音的通透淡然。 生活中有两种人,一种人格外在意别人的眼光;另一种人无论…

基于 OpenObserve 的轻量级分布式日志存储和追踪方案

一、OpenObserve 介绍 OpenObserve 是一个基于 Rust 开发的开源云原生可观察性平台&#xff0c;专为处理海量数据&#xff08;如日志、指标和追踪数据&#xff09;而设计&#xff0c;具有高性能、低成本和易用性等特点。 核心功能和特点&#xff1a; 低成本存储&#xff1a;…

python分配方案数 2023年信息素养大赛复赛/决赛真题 小学组/初中组 python编程挑战赛 真题详细解析

python分配方案数 2023全国青少年信息素养大赛Python编程挑战赛复赛真题解析 博主推荐 所有考级比赛学习相关资料合集【推荐收藏】 1、Python比赛 信息素养大赛Python编程挑战赛 蓝桥杯python选拔赛真题详解 蓝桥杯python省赛真题详解 蓝桥杯python国赛真题详解 2、Py…

【后端高阶面经:架构篇】52、微服务架构:微服务是银弹吗?

一、单体架构的困境:微服务诞生的背景 (一)巨石应用的五大痛点 开发效率低下 单体应用WAR包体积可达数百MB,单次全量编译耗时超30分钟,即使修改一行代码也需重新构建整个项目。案例:某电商早期单体应用包含10万行代码,每次发布需协调15个团队,合并冲突处理耗时占比达4…

C57-断言函数assert

一 基本语法 1. 作用 调试工具&#xff1a;用于运行时检查条件是否成立&#xff0c;若失败则终止程序并报错&#xff08;文件名、行号、条件&#xff09;。 2. 语法 #include <assert.h> assert(condition); // condition为假时触发断言3. 行为 条件为真&#xff1…

免费文本转语音工具体验:祈风TTS使用

简介&#xff1a;语音生成的另一种方式 现在很多人通过视频记录生活&#xff0c;表达观点。拍摄剪辑不难&#xff0c;配音成了常见难题。部分人对自己的声音不够自信&#xff0c;也有人在特定场景下不便出声。文本转语音工具可以成为解决方案。 常见的TTS&#xff08;Text To…

Redis持久化机制详解

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

Mistral 推出全新开发者平台Agents API

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

融智学三阶进化模型的全要素可视化解析

摘要&#xff1a;本文提出一种三阶进化模型&#xff0c;通过可视化图表与数学公式阐述人类智慧与人工智能的融合路径。研究构建Mermaid流程图展示"人类智力→形式化智慧→通用AI→超级AI→人机协同"的演进过程&#xff0c;并引入道函数$f_{\mathrm{Tao}}(\mathrm{Ob}…

颠覆传统!单样本熵最小化如何重塑大语言模型训练范式?

颠覆传统&#xff01;单样本熵最小化如何重塑大语言模型训练范式&#xff1f; 大语言模型&#xff08;LLM&#xff09;的训练往往依赖大量标注数据与复杂奖励设计&#xff0c;但最新研究发现&#xff0c;仅用1条无标注数据和10步优化的熵最小化&#xff08;EM&#xff09;方法…

simulink mask、sfunction和tlc的联动、接口

这里全部是讲的level2 sfunction&#xff08;用m语言编写&#xff09;&#xff0c;基于matlab 2020a。 1.mask的参数操作 1&#xff09;mask通过set_param和get_param这2个函数接口对mask里面定义的Parameters&Dialog的参数的大部分属性进行读写&#xff0c;一般是Value值…