二叉树经典OJ题(2)

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

. - 力扣(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;}};

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

. - 力扣(LeetCode)

思路1:

//策略1 1、如果一个在我的左子树,一个在我的右子树,那么我就是最近公共祖先//      2、如果两个走在我的左,就去左找  都不在我的左,那就去我的右找//      3、如果我自己就是,那另一个必然是我的孩子 返回我自己
class Solution {
public:bool isintree(TreeNode* root, TreeNode* x){if(root==nullptr) return false;else return root==x||isintree(root->left,x)||isintree(root->right,x);}TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode*&p, TreeNode*&q){if(root==nullptr) return nullptr;if(root==p||root==q) return root;//此时就要去看看我的左子树和右子树找一找bool pleft=isintree(root->left,p);bool pright=!pleft;bool qleft=isintree(root->left,q);bool qright=!qleft;if(pleft&&qright ||qleft&&pright) return root;else if(pleft&&qleft) return lowestCommonAncestor(root->left,p,q);else return lowestCommonAncestor(root->right,p,q);}
};

思路2:

class Solution {
public://策略2:利用dfs将p和q的路径存到容器中,然后转化成链表相交的问题 TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q){if(root==p||root==q) return root;stack<TreeNode*> Ppath;stack<TreeNode*> Qpath;dfs(root,p,Ppath);//找pdfs(root,q,Qpath);//找q//此时已经找到了两条目标路径,然后让长的那一条pop直到和另一条相等while(Ppath.size()!=Qpath.size()){if(Ppath.size()>Qpath.size()) Ppath.pop();else Qpath.pop();}//此时两个一起出,直到相等就返回while(Ppath.top()!=Qpath.top()){Ppath.pop();Qpath.pop();}return Ppath.top();}bool dfs(TreeNode* root, TreeNode* x,stack<TreeNode*>&path){if(root==nullptr) return false;//此时可以入栈,然后去左边和右边找一下path.push(root);//无论如何都入if(root==x||dfs(root->left,x,path)||dfs(root->right,x,path)) return true;//左边或右边找到,返回true//两边都没有找到,说明root不是我们想要的,出栈并返回false;path.pop();//都没找到,就得回溯return false;}
};

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

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

class Solution {
public:void inorder(TreeNode* cur,TreeNode*&prev){if(cur==nullptr) return;//cur指向的就是中序遍历的结果inorder(cur->left,prev);//这里出现的cur就是中序的结果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;}
};

 技巧:在递归过程中,我们想要有一个变量记录全过程(该题中的prev),第一种方法就是设置成全局变量,第二种方法就是传引用。

四、前序和中序遍历序列构建二叉树

. - 力扣(LeetCode)

class Solution {
public:TreeNode* _buildTree(vector<int>& preorder, vector<int>& inorder,int&pi,int begin,int end) {//先创建该节点if(begin>end) return nullptr;TreeNode*root=new TreeNode(preorder[pi]);//然后根据该节点分割左右区间 在中序数组中找到树int rooti=begin;while(rooti<=end){if(inorder[rooti]==preorder[pi]) break;++rooti;}//划分区间去左子树和右子树找++pi;root->left=_buildTree(preorder,inorder,pi,begin,rooti-1);root->right=_buildTree(preorder,inorder,pi,rooti+1,end);return root;}TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {//前序遍历:根 左子树 右子树    一个指针去遍历前序找根//中序遍历:左子树 根 右子树    划分左右区间//前序帮我们找根,中序帮我们划分区间int pi=0;//帮助我们按顺序遍历前序数组return _buildTree(preorder,inorder,pi,0,inorder.size()-1);}
};

五、中序和后序序列遍历构建二叉树

. - 力扣(LeetCode)

class Solution {
public:TreeNode* _buildTree(vector<int>& inorder, vector<int>& postorder,int&pi,int begin,int end){if(begin>end) return nullptr;TreeNode*root=new TreeNode(postorder[pi]);//肯定要先建立根//开始划分区间int rooti=begin;while(rooti<=end) {if(inorder[rooti]==postorder[pi]) break;++rooti;}//开始延伸,先延伸右子树,再延伸左子树--pi;root->right= _buildTree(inorder,postorder,pi,rooti+1,end);root->left= _buildTree(inorder,postorder,pi,begin,rooti-1);return root;}//后序遍历 左子树 右子树 根//中序遍历 左子树 根 右子树//后序遍历帮我们找根。   中序遍历帮我们划分左右区间TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder){int n=inorder.size();int pi=n-1;return _buildTree(inorder,postorder,pi,0,n-1);}
};

六、非递归实现二叉树的前序遍历

. - 力扣(LeetCode)

class Solution {
public://根 左子树 右子树//根、左子树、然后再栈里面搞右子树vector<int> preorderTraversal(TreeNode* root) {stack<TreeNode*> st;vector<int> ret;if(root==nullptr) return ret;TreeNode*cur=root;//1、访问左路节点//2、访问左路节点的右子树while(!st.empty()||cur) //cur不为空表示当前的树还没访问,栈不为空表示还有右子树没有访问{while(cur){ret.push_back(cur->val);st.push(cur);cur=cur->left;}//开始去访问右子树TreeNode* t=st.top();st.pop();//转化成子问题,去访问节点的右树cur=t->right;}return ret;}
};

七、非递归实现二叉树的中序遍历

. - 力扣(LeetCode)

class Solution {
public:
//中序  左子树 根 右子树 
//1 左路节点
//2 左子树的右路节点
//从栈里取到左路节点,意味着左路节点,以为着这个节点的左子树已经访问完了。
// 非递归实现 vector<int> inorderTraversal(TreeNode* root) {stack<TreeNode*> st;vector<int> ret;if(root==nullptr) return ret;TreeNode*cur=root;while(cur||!st.empty()){while(cur){st.push(cur);cur=cur->left;}//此时,从栈中拿出来TreeNode* t=st.top();st.pop();ret.push_back(t->val);cur=t->right;}return ret;}
};

八、非递归实现二叉树的后序遍历

. - 力扣(LeetCode)

class Solution {
public:vector<int> postorderTraversal(TreeNode* root) { stack<TreeNode*> st;vector<int> ret;if(root==nullptr) return ret;TreeNode*cur=root;//1、访问左路节点//2、访问左路节点的右子树TreeNode*prev=nullptr;while(!st.empty()||cur) //cur不为空表示当前的树还没访问,栈不为空表示还有右子树没有访问{while(cur){st.push(cur);cur=cur->left;}//开始去访问右子树TreeNode* t=st.top();if(t->right==nullptr||t->right==prev){ret.push_back(t->val);st.pop();prev=t;}//从栈中弹出的节点,我们只能确定其左子树肯定访问完了,但是无法确定右子树是否访问过。else cur=t->right;}return ret;}
};

     还有一种思路就是,因为我们的结果是存在一个数组去返回的,因此我们可以按照前序遍历的逻辑:将问题拆分成 右路节点和右路节点的左子树。然后按照 根、右子树、左子树的顺序去访问(和后序相反),最后再逆置我们的返回数组即可。这是一种取巧的方法,但是能成功是因为该题是将结果放到一个数组中返回的,如果该题是要求我们边遍历边访问,比如打印,那么该方法就不可行。

class Solution {
public:vector<int> postorderTraversal(TreeNode* root) {stack<TreeNode*> st;vector<int> ret;if(root==nullptr) return ret;TreeNode*cur=root;//1、访问右路节点//2、访问右路节点的左子树while(!st.empty()||cur) //cur不为空表示当前的树还没访问,栈不为空表示还有左子树没有访问{while(cur){ret.push_back(cur->val);st.push(cur);cur=cur->right;}//开始去访问左子树TreeNode* t=st.top();st.pop();//转化成子问题,去访问节点的右树cur=t->left;}reverse(ret.begin(),ret.end());return ret;}
};

 九、小总结

1、二叉搜索树涉及到升序的情况,一般是根中序遍历建立联系

2、前序和中序构建二叉树,以及中序和后序构建二叉树,本质上是利用一个序列找根,另一个序列去划分问题。同时我们会发现其实后序遍历如果反着来的话大多数情况下可以转化成类似前序遍历,比如4、5题和7、8题,都可以用前序遍历的思路去解决后序遍历。

3、非递归实现二叉树的前中后序遍历,本质上是将问题拆分为1、访问左路节点 2、访问左路节点的右子树。需要用一个辅助栈去帮助我们记录节点。

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

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

相关文章

【springCloud】版本学习

Spring Cloud介绍 官网地址&#xff1a;https://spring.io/projects/spring-cloud Spring Cloud 是一个基于 Spring Boot 的微服务架构解决方案&#xff0c;它提供了一系列工具和模式来帮助开发者构建分布式系统。Spring Cloud 的组件和模式包括配置管理、服务发现、断路器、…

【Linux】tcpdump P3 - 过滤和组织返回信息

文章目录 基于TCP标志的过滤器格式化 -X/-A额外的详细选项按协议(udp/tcp)过滤低详细输出 -q时间戳选项 本文继续展示帮助你过滤和组织tcpdump返回信息的功能。 基于TCP标志的过滤器 可以根据各种TCP标志来过滤TCP流量。这里是一个基于tcp-ack标志进行过滤的例子。 # tcpdump…

vue源码解析——diff算法/双端比对/patchFlag/最长递增子序列

虚拟dom——virtual dom&#xff0c;提供一种简单js对象去代替复杂的 dom 对象&#xff0c;从而优化 dom 操作。virtual dom 是“解决过多的操作 dom 影响性能”的一种解决方案。virtual dom 很多时候都不是最优的操作&#xff0c;但它具有普适性&#xff0c;在效率、可维护性之…

《由浅入深学习SAP财务》:第2章 总账模块 - 2.7 总账模块报表 -2.7.2 对外报表:现金流量表

2.7.2 对外报表&#xff1a;现金流量表 现金流量表包括直接法和间接法。使用SAP出具现金流量表&#xff0c;一般只能出具直接法报表。间接法是指按照净利润倒推出现金流量的发生额&#xff0c;由于其中存在人为“分析”的因素&#xff0c;很难直接通过科目的加加减减得出所需要…

Fiddler工具的操作和功能时-----定位到步骤图(助力抓包)

前言&#xff1a; 继续上一篇&#xff0c;已经对fiddler的安装、配置和代理的问题进行了讲解&#xff1a; Fiddle配置代理&#xff0c;保手机模拟器访问外部网络-CSDN博客 本章&#xff0c;讲对一些fiddler的操作进行一系列讲解&#xff01;Fiddler作为一款网络调试工具&…

Java复习第十七天学习笔记(转发、重定向,GET,POST),附有道云笔记链接

【有道云笔记】十七 4.3 转发、重定向、Get、POST、乱码 https://note.youdao.com/s/GD5TRksQ 一、转发 转发&#xff1a;一般查询了数据之后&#xff0c;转发到一个jsp页面进行展示 req.setAttribute("list", list); req.getRequestDispatcher("student_lis…

浅谈函数 fscanf/sscanf 和 fprintf/sprintf

目录 一&#xff0c;fprintf 的介绍和使用1. 函数介绍2. 函数使用 二&#xff0c;fscanf 的介绍和使用1. 函数介绍2. 函数使用 三&#xff0c;sprintf 的介绍和使用1. 函数介绍2. 函数使用 四&#xff0c;sscanf 的介绍和使用1&#xff0c;函数介绍2&#xff0c;函数使用 五&am…

关于MCU产品开发参数存储的几种方案

关于MCU产品开发参数存储的几种方案 Chapter1 关于MCU产品开发参数存储的几种方案Chapter2 单片机参数处理[保存与读取]Chapter3 嵌入式设备参数存储技巧Chapter4 STM32硬件I2C的一点心得(AT24C32C和AT24C64C) Chapter1 关于MCU产品开发参数存储的几种方案 原文链接 在工作中…

【系统分析师】计算机网络

文章目录 1、TCP/IP协议族1.1 DHCP协议1.2 DNS协议1.3网络故障诊断 2、网路规划与设计2.1逻辑网络设计2.2物理网络设计2.3 分层设计 3、网络接入3.1 接入方式3.2 IPv6地址 4、综合布线技术5、物联网5.1物联网概念与分层5.2 物联网关键技术 6、云计算7、网络存储技术&#xff08…

C语言中局部变量和全局变量是否可以重名?为什么?

可以重名 在C语言中, 局部变量指的是定义在函数内的变量, 全局变量指的是定义在函数外的变量 他们在程序中的使用方法是不同的, 当重名时, 局部变量在其所在的作用域内具有更高的优先级, 会覆盖或者说隐藏同名的全局变量 具体来说: 局部变量的生命周期只在函数内部,如果出了…

AI来了,Spring还会远吗?(Spring AI初体验)

目录 一、创建项目二、first demo1、application.properties2、ChatController3、结果 三、个人思考 一、创建项目 官方文档的Getting Started 最低要求&#xff1a;JDK17 阿里云的Server URL&#xff08;https://start.aliyun.com/&#xff09;搜不到Spring AI&#xff0c;…

数据库:SQL分类之DQL详解

1.DQL语法 select 字段列表 from 表名列表 where 条件列表 group by 分组字段列表 having 分组后条件列表 order by 排序字段列表 limit 分页参数 基本查询 条件查询&#xff08;where&#xff09; 聚合函数&#xff08;count、max、min、avg、sum &#xff09; 分组查询&…

C语言100道练习题打卡(1)

1 有1&#xff0c;2&#xff0c;3&#xff0c;4四个数字&#xff0c;能组成多少个互不相同且不重复的三位数&#xff0c;都是多少 #include<stdio.h> //有1&#xff0c;2&#xff0c;3&#xff0c;4四个数字&#xff0c;能组成多少个互不相同且不重复的三位数&#xff…

分享一些有趣的 Linux 命令

1、sl 会显示一辆火车穿过你的终端屏幕 2、cmatrix 在终端中显示类似于《黑客帝国》电影中的绿色数字雨效果 3、fortune 显示一个随机的名人名言或者笑话 4、cowsay 让一头牛说出你输入的话 5、toilet 在终端中将输入的文本以艺术字体的形式呈现 6、figlet 类似于 toile…

ssm051网上医院预约挂号系统+jsp

网上医院预约挂号系统设计与实现 摘 要 如今的信息时代&#xff0c;对信息的共享性&#xff0c;信息的流通性有着较高要求&#xff0c;因此传统管理方式就不适合。为了让医院预约挂号信息的管理模式进行升级&#xff0c;也为了更好的维护医院预约挂号信息&#xff0c;网上医院…

Vue入门:天不生Vue,前端万古如长夜 - Vue从入门到放弃

目录 &#x1f44b; Vue环境搭建 1.安装node.js 2.配置环境变量 3.VSCode配置 4.安装Vue CLI 5.在VS Code中打开Vue项目 6.运行Vue项目 &#x1f440; Vue基础学习 1.引入vue.js 2.数据方法 3.生命周期&#xff01; 4.模板语法 5.对象语法 6.条件渲染 7.列表渲…

简历上写熟悉Linux下常用命令?直接寄

大家写简历技术栈时&#xff0c;都觉得越多越好&#xff0c;其中一条&#xff0c;熟悉Linux下常用命令&#xff1f;其实开发中Linux不是必备考点&#xff0c;除了运维&#xff0c;真正用的多的仅仅cd ls mkdir等&#xff0c;但当面试官问到上面命令时&#xff0c;是不是就傻眼了…

Java使用OpenOffice将office文件转换为PDF

Java使用OpenOffice将office文件转换为PDF 1. 先行工作1.1 OpenOffice官网下载1.2 JODConverter官网下载1.3 下载内容 2.介绍3. 安装OpenOffice服务3.1.Windows环境3.2 Linux环境 4. maven依赖5. 转换代码 1. 先行工作 请注意&#xff0c;无论是windows还是liunx环境都需要安装…

基于深度学习的花卉检测系统(含PyQt界面)

基于深度学习的花卉检测系统&#xff08;含PyQt界面&#xff09; 前言一、数据集1.1 数据集介绍1.2 数据预处理 二、模型搭建三、训练与测试3.1 模型训练3.2 模型测试 四、PyQt界面实现参考资料 前言 本项目是基于swin_transformer深度学习网络模型的花卉检测系统&#xff0c;…

建模设计软件 Archicad 27 for mac激活版

在建筑设计领域&#xff0c;每一次技术的革新都意味着设计效率和质量的飞跃。Archicad 27 for Mac&#xff0c;就是这样一款引领行业变革的设计软件。 Archicad 27凭借出色的性能优化和强大的功能更新&#xff0c;为Mac用户带来了前所未有的建筑设计体验。它支持BIM&#xff08…