【OJ】C++ | 二叉树进阶 · 合集(2)

摘要:根据二叉树创建字符串、二叉树的最近公共祖先、二叉树的层序遍历

前言:承接上文,本文继续提供二叉树进阶有关题目的解法。如有错误,烦请指正。


目录

1. 根据二叉树创建字符串

题解及代码

2. 二叉树的最近公共祖先

题解及代码

3. 二叉树的层序遍历

题解

代码


1. 根据二叉树创建字符串

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

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

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

示例 1:

输入:root = [1,2,3,4]
输出:"1(2(4))(3)"
解释:初步转化后得到 "1(2(4)())(3()())" ,但省略所有不必要的空括号对后,字符串应该是"1(2(4))(3)" 。

示例 2:

输入:root = [1,2,3,null,4]
输出:"1(2()(4))(3)"
解释:和第一个示例类似,但是无法省略第一个空括号对,否则会破坏输入与输出一一映射的关系。

提示:

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

题解及代码

  • 方式一:递归 + 处理括号。对于每个递归的子问题:括号有4种情况,①root()(sub_right);②root(sub_left)(sub_right);③root(sub_left);④root;以上这4种情况可归纳为:(一)sub_right 存在(①②);(二)sub_right 不存在(③④).
    class Solution {
    public:void _tree2str(TreeNode* rootP,string& ret){if(rootP == nullptr)return;ret += to_string(rootP->val);if(rootP->right != nullptr){if(rootP->left == nullptr)//①{ret += "()";ret += '(';_tree2str(rootP->right,ret);ret += ')';}   else//②{ret += '(';_tree2str(rootP->left,ret);ret += ')';ret += '(';_tree2str(rootP->right,ret);ret += ')';}}else{if(rootP->left == nullptr)//③{_tree2str(rootP->right,ret);_tree2str(rootP->left,ret);}else//④{ret += '(';_tree2str(rootP->left,ret);ret += ')';}      }}string tree2str(TreeNode* root) {if (root == nullptr)return "";string ret;_tree2str(root,ret);return ret;}
    };
  • 方式二:模拟递归(“非递归”) + 处理括号(此处建议看过 上一篇二叉树进阶题合集最后三题 对于非递归的思路的讲解之后再看) 

紧承上篇的结尾的总结,则我们可容易得出如下图解:

①进入root层:递归进入 root 层,并判断作左子树是否为空,为空则继续判断右子树;
②返回root层:左子树为空/递归完,判断右子树是否为空,不为空就接着递归右子树;
③第二次返回root层:右子树为空/递归完,判断右子树是否访问完毕,访问完则结束。
关键:区分是第几次返回root层。→ 可以通过一个变量来记录。

class Solution {
public:string tree2str(TreeNode* root) {if (root == nullptr)return "";string ret;stack<pair<TreeNode*,bool>> st;TreeNode* CurP = root;while (CurP || !st.empty()) {while (CurP) {st.push(make_pair(CurP,1));ret += to_string(CurP->val);//cout << "ret += to_string(CurP->val);";if(CurP->left || CurP->right)ret += '(';CurP = CurP->left;}pair<TreeNode*,bool>& topPr = st.top();TreeNode* tp = topPr.first;if (tp->right == nullptr){if(tp->left != nullptr)ret += ")";//左右子树的结点没有任何括号st.pop();//该层递归结束} else // topP右不空{if(topPr.second == 1) //右子树存在且未被访问{ret += ")(";topPr.second = false;CurP = tp->right;}else //右子树存在但被访问完了{ret += ')';st.pop();//该层递归结束}}}//_tree2str(root,ret);return ret;}
};

2. 二叉树的最近公共祖先

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

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

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

示例 1:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。

示例 2:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。

示例 3:

输入:root = [1,2], p = 1, q = 2
输出:1

题解及代码

方式一:根据最近公共节点的特点来解题。
根据题目描述可知:p,q两节点一定分别位于最近公共祖先节点的左子树或右子树(或者其中一个节点本身就是最近公共节点)

class Solution {
public:bool Findsubtree(TreeNode* root,TreeNode* node){if(root == node)return true;if(root == nullptr)return false;return Findsubtree(root->right,node) || Findsubtree(root->left,node);}TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {if(root == nullptr)return nullptr;if(root == p || root == q)return root;bool pInLeft = Findsubtree(root->left,p);//p位于root的左子树bool pInRight = !pInLeft;//p位于root的右子树(同:不位于root的左子树)bool qInLeft = Findsubtree(root->left,q);//同上bool qInRight = !qInLeft;//同上if((pInLeft && qInRight) || (pInRight && qInLeft))//若p,q分别位于左右子树,则该层root为最近公共祖先节点return root;if(pInLeft && qInLeft)//如果都位于左子树则得递归到左子树去找最近公共祖先节点return lowestCommonAncestor(root->left,p,q);if(pInRight && qInRight)//如果都位于右子树则得递归到右子树去找最近公共祖先节点return lowestCommonAncestor(root->right,p,q);return nullptr;//按代码运行逻辑不会走到这句,但是这里对返回值的编译检查比较严格。}
};

方式二:找到从根节点分别“走”到p,q节点的路径。在这两个路径中,从p,q节点开始往前看,第一个相等的结点就是最近公共祖先。即:
pathOfp{x,x,x,x,x,a,b,……,p}
pathOfq{x,x,x,x,x,y,z,w,……,q}
关键在于:如何找到这两条路径?
​​答:找到路径中所含的每个节点的特征——该节点的子树中一定含有p或q节点(或者该节点本身就是p或q节点)。→ 找路径的思路:依次递归每个节点,递归到该节点的时候,该节点push入栈,再去递归该节点的左子树和右子树,如果该节点的左子树和右子树中有没有要找的结点,那么该节点不属于路径中的结点,则pop该节点。接着去递归别的节点。

如该图所示,目标是从根节点找到节点4。首先,节点3递归左子树到节点5,节点5递归左子树到节点6,节点6的左子树为空未找到节点4,节点6的左子树返回false,节点6的左子树同理返回false,由于节点6的左右子树都为false,即都未找到节点4则节点6不是该路径中的结点,节点6将被pop出栈,并且,节点6作为节点5的左子树,递归的结果点为false。然后继续递归节点5的右子树。

class Solution {
public:bool FindPath(TreeNode* root,TreeNode* node,stack<TreeNode*>& path){   if(root == nullptr){return false;}path.push(root);if(root == node)return true;if(FindPath(root->left,node,path))return true;if(FindPath(root->right,node,path))return true;path.pop();return false;}TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {if(root == nullptr)return nullptr;if(root == p || root == q)return root;stack<TreeNode*> pathOfp,pathOfq;FindPath(root,p,pathOfp);FindPath(root,q,pathOfq);while(pathOfp.top() != pathOfq.top()){if(pathOfp.size() < pathOfq.size()){pathOfq.pop();}else{pathOfp.pop();}}return pathOfp.top();}
};

3. 二叉树的层序遍历

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

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

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]

示例 2:

输入:root = [1]
输出:[[1]]

示例 3:

输入:root = []
输出:[]

提示:

  • 树中节点数目在范围 [0, 2000] 内
  • -1000 <= Node.val <= 1000

题解

C++初阶 | [十] stack 和 queue在该篇文章中的【queue OJ】部分的内容给本题的出了思路。

下面给的代码为思路三的解法。

代码

class Solution {
public:vector<vector<int>> levelOrder(TreeNode* root) {if(root == nullptr)return vector<vector<int>>();vector<vector<int>> ret;size_t levelSize = 0;queue<TreeNode*> qTree;TreeNode* CurP = root;qTree.push(CurP);levelSize = qTree.size();while(!qTree.empty()){vector<int> tmp = {};while(levelSize--){CurP = qTree.front();if(CurP->left){qTree.push(CurP->left);}if(CurP->right){qTree.push(CurP->right);}tmp.push_back(CurP->val);qTree.pop();}ret.push_back(tmp);levelSize = qTree.size();}return ret;}
};

END

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

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

相关文章

Java | Leetcode Java题解之第121题买卖股票的最佳时机

题目&#xff1a; 题解&#xff1a; public class Solution {public int maxProfit(int prices[]) {int minprice Integer.MAX_VALUE;int maxprofit 0;for (int i 0; i < prices.length; i) {if (prices[i] < minprice) {minprice prices[i];} else if (prices[i] -…

用幻灯片讲解C++中的C语言风格数组

用幻灯片讲解C中的C语言风格数组 1.栈内存中的C风格数组 糟糕的可用性&#xff0c;但你将在遗留代码中看到它们。相同类型的对象块。大小必须是常量表达式。第一个元素的索引为0&#xff0c;即数组索引从0开始。 注意一下数组的初始化&#xff0c;使用了C11标准之后的统一初始…

【2024年5月备考新增】】 考前篇(26)《必备资料(9) - 论文串讲-范围管理》

过程定义输入工具技术输出实际应用规划范 围管理编制范围管理计划: 书面描述将如何定 义、制定确认项目 范围的过程,其主 要作用是在整个项 目中对如何管理范 围提供指南和方向1、项目章程2、项目管理计划.质量管理计划 3、事业环境因素 .项目生命周期描4、组织过程资产 述.开…

react ant design Upload 多文件上传 beforeUpload 会调用很多次,怎么只获取一次

当使用Ant Design的Upload组件实现多文件上传时&#xff0c;beforeUploadHandler函数会被每个选中的文件调用一次。如果您只想获取一次选中的文件而不是每个文件都触发一次处理逻辑&#xff0c;可以采取以下方法&#xff1a; 使用 useRef 钩子保存文件列表&#xff1a;可以使用…

Nginx监控与告警:确保服务稳定运行

在今天的网络世界中&#xff0c;Nginx已经成为许多网站和应用程序的首选反向代理和Web服务器。然而&#xff0c;随着流量的增长和复杂性的增加&#xff0c;确保Nginx服务的稳定运行变得至关重要。本文将探讨如何有效地监控Nginx&#xff0c;并设置告警机制&#xff0c;以便在潜…

cefpython3打包windows应用

序 最近使用cefpython3开发程序&#xff0c;网上找了一圈打包工具都没有效果&#xff0c;最后在github中翻到使用cx_Freeze进行打包。 代码 from distutils.sysconfig import get_python_lib from os.path import join from glob import glob from cx_Freeze import setup, …

数学建模--特殊的图

目录 1.二部图 &#xff08;1&#xff09;简单认识 &#xff08;2&#xff09;定义 &#xff08;3&#xff09;判定定理 &#xff08;4&#xff09;定理理解 2.匹配问题 &#xff08;1&#xff09;匹配 &#xff08;2&#xff09;完备&&完美匹配 &#xff08;3…

JTS库的讲解及使用

JTS&#xff08;Java Topology Suite&#xff09;是一套用于创建、操作和分析二维几何对象的Java库。JTS提供了丰富的几何操作和分析功能&#xff0c;是GIS&#xff08;地理信息系统&#xff09;应用中的重要工具。以下是JTS库的一些主要功能及其详细使用示例&#xff1a; 1. …

【Python】使用 Pandas 进行均值填充:处理缺失数据的实用指南

缘分让我们相遇乱世以外 命运却要我们危难中相爱 也许未来遥远在光年之外 我愿守候未知里为你等待 我没想到为了你我能疯狂到 山崩海啸没有你根本不想逃 我的大脑为了你已经疯狂到 脉搏心跳没有你根本不重要 &#x1f3b5; 邓紫棋《光年之外》 在数据分析…

Python 入门教程详细版全集(两周速成)

一、初始Python 打开CMD&#xff08;命令提示符&#xff09;程序&#xff0c;输入Python并回车。然后&#xff0c;在里面输入代码回车即可立即执行。 Tip1:找不到“命令提示符”程序在哪里&#xff1f; 使用快捷键&#xff1a;win r;打开运行框&#xff0c;输入cmd后回车即可…

点点点还有没有做下去的必要

大家好&#xff0c;我是洋子&#xff0c;最近工作特别忙&#xff0c;好久没更文章了 因为组织架构调整&#xff0c;原先的组长调离我所在已经3年多的业务线&#xff0c;我就承担起组长的角色了&#xff0c;除了日常跟进需求测试&#xff0c;还跟RD、跨业务线负责人开会&#x…

chat2-Client发送数据给Server

本文档描述了Client发送消息给Server&#xff0c; Server端打印接收的消息 一、Client 1.1.客户端的类Client.java中添加如下的start()方法 (表示启动客户端功能的方法)&#xff0c;并调用 /**start方法&#xff0c;作为客户端开始工作的方法*/ public void start(){ …

fastadmin 放服务器上后出现大量的502 亲身经历

fastadmin 放服务器上后出现大量的502 今天发生了一个特别无语的事情,那就是服务器上出现大量的502报错 因为之前一直都运行的好好的,突然今天就开始不间断的报502的错误,最开始我没有怀疑到服务器上,浪费了一天的时间进行排查! 因为域名挂在cf上,然后我又在cf上做了各种…

自然语言处理(NLP)—— 神经网络语言处理

1. 总体原则 1.1 深度神经网络&#xff08;Deep Neural Network&#xff09;的训练过程 下图展示了自然语言处理&#xff08;NLP&#xff09;领域内使用的深度神经网络&#xff08;Deep Neural Network&#xff09;的训练过程的简化图。 在神经网络的NLP领域&#xff1a; 语料…

深入解析Java中List和Map的多层嵌套与拆分

深入解析Java中List和Map的多层嵌套与拆分 深入解析Java中List和Map的多层嵌套与拆分技巧 &#x1f4dd;摘要引言正文内容什么是嵌套数据结构&#xff1f;例子&#xff1a; 遍历嵌套List和Map遍历嵌套List遍历嵌套Map 拆分嵌套数据结构拆分嵌套List拆分嵌套Map &#x1f914; Q…

PHP面向对象编程总结

PHP面向对象编程总结 学习PHP时&#xff0c;面向对象编程&#xff08;OOP&#xff09;往往是一个重要的里程碑。PHP的OOP功能提供了一种更加模块化、可扩展和易于维护的代码结构。在本文中&#xff0c;我们将深入探讨PHP面向对象编程的各个方面&#xff0c;包括类与对象、访问控…

【C#】委托和事件

目录 1.概念 2.自定义的委托 3.系统定义的委托 4.委托和事件的区别 1.概念 数组我们都知道是一组数据的容器&#xff0c;而委托很相似&#xff0c;不过它是一组函数的容器。 如果把调用一次函数看做释放一个技能&#xff0c;那调用一次委托则是释放一套技能连招 下面看看…

排序-希尔排序

介绍 希尔排序属于那种没有了解过的直接看代码一脸懵逼的&#xff0c; 所以同学们尽量不要直接看代码&#xff0c;仔细阅读本篇博客内容。 插入排序本来算是一个低效排序&#xff0c; 一次只可以挪动一个数据&#xff0c; 但是&#xff0c;它的强来了&#xff01;&#xff01…

网吧|基于SprinBoot+vue的网吧管理系统(源码+数据库+文档)

网吧管理系统 目录 基于SprinBootvue的网吧管理系统 一、前言 二、系统设计 三、系统功能设计 1 管理员功能模块 2 网管功能模块 3 会员功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#…