【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标准之后的统一初始…

数学建模--特殊的图

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

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

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

chat2-Client发送数据给Server

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

自然语言处理(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…

排序-希尔排序

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

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

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

Arduino 按钮及弹跳

所需元件 可插入面包板的按钮1个 220Ω电阻1个 10kΩ电阻1个 3mm或5mm LED 1个 面包板1块 Arduino Uno开发板1块 面包板连接线数条 使用外接电阻 将5V接到按钮&#xff0c;按钮的另一端串联1个10kΩ电阻再接地&#xff0c;这样的接法被称为下拉电阻(pull-down resistor)。若测…

【30天精通Prometheus:一站式监控实战指南】第14天:jmx_exporter从入门到实战:安装、配置详解与生产环境搭建指南,超详细

亲爱的读者们&#x1f44b;   欢迎加入【30天精通Prometheus】专栏&#xff01;&#x1f4da; 在这里&#xff0c;我们将探索Prometheus的强大功能&#xff0c;并将其应用于实际监控中。这个专栏都将为你提供宝贵的实战经验。&#x1f680;   Prometheus是云原生和DevOps的…

【LeetCode算法】第104题:二叉树的最大深度

目录 一、题目描述 二、初次解答 三、官方解法 四、总结 一、题目描述 二、初次解答 1. 思路&#xff1a;二叉树的先序遍历。首先判断根节点是否是空&#xff0c;其次判断根节点是否是叶子节点&#xff0c;再者递归获取左子树的深度、右子树的深度&#xff0c;最后返回左子…

【Mac】Lightroom Classic 2024(LrC 2024中文版) v13.1安装教程

软件介绍 Lightroom Classic 2024 for Mac是一款功能强大的照片编辑和组织软件&#xff0c;专为专业摄影师和爱好者设计。它提供了一系列工具和功能来增强和管理您的数码照片。Lightroom Classic 2024在照片组织和管理方面进行了重大改进。它新增了一个智能化的“发现”面板&a…

1. MySQL 数据库的基本操作

文章目录 【 1. SQL 的书写规则 】大小写规则常量的表示注释 【 2. RDBMS 术语 】Table 表Filed 域/字段Column 列Record 记录NULL 空值Constraint 约束数据的完整性范式 【 3. 数据库基本操作函数 】3.1 SHOW DATABASES 显示数据库3.2 CREATE DATABASE 创建数据库3.3 ALTER DA…

回炉重造java----JUC(第一天)

目录 JUC前置知识①进程和线程的区别&#xff1f;②并行和并发的区别&#xff1f;③异步调用和同步调用的区别&#xff1f;④创建线程的方法⑤线程的上下文切换⑥TimeUtil⑦Interrupt⑧如何在一个线程中终止另外一个线程&#xff1f;⑨线程的状态共享模型之管程 阻塞式&#x…

LLVM后端__llc中值定义信息的查询方法示例

关于LiveIntervals pass中相关数据结构的含义&#xff0c;在寄存器分配前置分析(5.1) - LiveInterval这篇博客中已经做了清晰的讲解&#xff0c;此处不再赘述&#xff0c;本文主要讲解值定义信息VNInfo的使用方法和注意事项。 1. VNInfo含义 在LLVM的源码中&#xff0c;VNInf…

视频汇聚EasyCVR综合安防平台对接GA/T1400公安视图库及应用方案

随着科技的不断进步&#xff0c;视频监控系统在公共安全领域发挥着越来越重要的作用。GA/T1400公安视图库作为公安视频图像信息应用系统的标准&#xff0c;为视频监控系统的对接提供了统一的规范和技术要求。 GA/T1400标准的应用范围广泛&#xff0c;涵盖了公安系统的视频图像信…

图解大模型分布式并行各种通信原语

背景 在分布式集群上执行大模型任务时候&#xff0c;往往使用到数据并行&#xff0c;流水线并行&#xff0c;张量并行等技术&#xff0c;这些技术本质上也就是对数据进行各种方案的切分&#xff0c;然后放到不同的节点上运算。不同节点在计算的过程中需要对数据分发或者同步等…

【精读文献】J. Environ. Manage.|青藏高原生态恢复项目下植被覆盖动态及其对生态系统服务的约束效应

目录 文章简介 01 文章摘要 02 研究背景、目标及创新点 2.1 研究背景 2.2 研究现状 03 研究区域与数据集 3.1 研究区域 3.2 研究数据 04 研究方法 4.1 趋势分析 4.2 残差趋势分析 4.3 偏相关 4.4 生态系统服务评价 4.5 约束线的定义和提取 05 研究结果 5.1 植被…