C++——二叉树进阶oj题

news2024/11/15 15:29:33

目录

  • 二叉树创建字符串
  • 二叉树的分层遍历1
  • 二叉树的分层遍历2
  • 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先
  • 二叉树搜索树转换成排序双向链表。
  • 根据一棵树的中序遍历与后序遍历构造二叉树
  • 根据一棵树的前序遍历与中序遍历构造二叉树

二叉树创建字符串

题目链接
思路:
二叉树递归前序遍历的变形,对于一个根,根据题意有四种情况
1、左右孩子都存在:正常前序遍历递归
2、只有左孩子没有右孩子:需要遍历左孩子,让右孩子返回空字符串。
3、只有右孩子没有左孩子:在遍历右孩子之前要在前面加上(),为的是和上面只有左孩子没有右孩子的情况区分。
4、左右孩子都不存在:均返回空字符串。
实现代码:

class Solution {
public:
    string tree2str(TreeNode* root) {
        if(root==nullptr)
        {
            return string();
        }
        string ret;
        ret+=to_string(root->val);
        if(root->left)
        {
            ret+="(";
            ret+=tree2str(root->left);
            ret+=")";
        }
        if(root->left==nullptr&&root->right!=nullptr)
        ret+="()";

        if(root->right)
        {
            ret+="(";
            ret+=tree2str(root->right);
            ret+=")";
        }
        return ret;

    }
};

二叉树的分层遍历1

在这里插入图片描述

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

题目链接
思路:
利用一个队列控制层序遍历的结点,因为题中要求返回vector<vector<int>>,所以层序遍历的同时要记录当前走到第几层了,第一层和第二层的元素不能放在同一个vector中。
定义一个queue<TreeNode*> q,先从根节点开始,将地址push到q中,设置一个T_level变量来标识层数,一开始设置为1,表示在二叉树的第一层,然后在q中每pop一个结点就让T_level-1,pop的同时如果左右孩子都不为空,那么把它的左右孩子也push,当T_level==0的时候,此时队列里就剩下下一层的元素了,把queue的size赋值给T_level,然后将刚才的vector尾插到vector<vector<int>>中,再开始下一层的遍历。
实现代码:

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> vv;
        if(root==nullptr)
        {
            return vv;
        }
        
        queue<TreeNode*> q;

        int T_level=1;
        q.push(root);

        while(!q.empty())
        {
            vector<int> tmp;

            while(T_level--)
            {
                tmp.push_back(q.front()->val);
                
                
                if(q.front()->left)
                {
                    q.push(q.front()->left);
                }
                if(q.front()->right)
                {
                    q.push(q.front()->right);
                }

                q.pop();
                
            }
            T_level=q.size();
            vv.push_back(tmp);
        }
        return vv;
    }
};

二叉树的分层遍历2

题目链接
思路:
将上一题的vector<vector<int>>逆置一下即可。
实现代码:

class Solution {
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        vector<vector<int>> vv;
        if(root==nullptr)
        {
            return vv;
        }
        
        queue<TreeNode*> q;

        int T_level=1;
        q.push(root);

        while(!q.empty())
        {
            vector<int> tmp;

            while(T_level--)
            {
                tmp.push_back(q.front()->val);
                
                
                if(q.front()->left)
                {
                    q.push(q.front()->left);
                }
                if(q.front()->right)
                {
                    q.push(q.front()->right);
                }

                q.pop();
                
            }
            T_level=q.size();
            vv.push_back(tmp);
        }
        reverse(vv.begin(),vv.end());

        return vv;
    }
};

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

题目链接
思路:
写一个Get_Path函数把到两个结点的路径用两个stack记录下来,然后让路径长的出栈,直到两个结点的路径长度相同,此时从两个栈的栈顶开始比对看是否有相同的结点,一旦发现相同的结点,这个结点就是要找的最近公共祖先。
实现代码:

class Solution {
public:
    bool Get_Path(TreeNode* &root, TreeNode* & FindNode,stack<TreeNode*>& path)//
    {
        if(root==nullptr)
        {
            return false;
        }

        path.push(root);


        if(root==FindNode)
        return true;
        
        if(Get_Path(root->left,FindNode,path))
        {
            return true;
        }

        if(Get_Path(root->right,FindNode,path))
        {
            return true;
        }

        //以root的左右孩子为起点没有找到FindNode
        path.pop();
        return false;
    }

    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        
        stack<TreeNode*> pPath;
        stack<TreeNode*> qPath;

        Get_Path(root,p,pPath);
        Get_Path(root,q,qPath);
        
		//两个栈倒着找
        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();
    }
};

二叉树搜索树转换成排序双向链表。

题目链接
思路:
最简单的一种思路:用vector把二叉搜索树遍历的序列存起来,然后遍历vector,按双向链表的方式把它们链接起来即可。
递归的思路:另外写一个InorderConvert函数,中序遍历递归构建双向链表,这里设计函数的时候prev变量要加引用,cur表示当前结点。
实现代码:

class Solution {
public:
	void InorderConvert(TreeNode*cur,TreeNode*&prev)
	{
		if(cur==nullptr)
		{
			return;
		}

		InorderConvert(cur->left, prev);
		//画图才能较好的理解
		cur->left=prev;
		if(prev)
		prev->right=cur;
		prev=cur;

		InorderConvert(cur->right,prev);
	}

    TreeNode* Convert(TreeNode* pRootOfTree) {
        
		TreeNode*prev=nullptr;
		InorderConvert(pRootOfTree,prev);
		
		//前面已经链接好了,后面找双向链表的头,然后返回即可
		TreeNode* head = pRootOfTree;
		while(head&&head->left)
		{
			head = head->left;
		}

		return head;
    }
};

根据一棵树的中序遍历与后序遍历构造二叉树

题目链接

在这里插入图片描述

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

思路:
模拟建树的过程:
在后序遍历postorder从后往前,可以依次确定一棵树的根在哪,确定根之后,
在中序遍历inorder中找到在后序遍历postorder中确定的根的下标N,
在中序遍历序列里再划分左右子树区间:[0,N-1]N[N+1,inorder.size()-1]
上面的例子中很显然第一次N==1
[0,0]是左子树区间,[2,4]是右子树区间
但是观察发现postorder的“根”从后往前,都是先右后左的,那么在确定根之后首先应该建立右子树,然后建立左子树。如果不这样的话,先建立左子树的话,结合上一步确定的左子树区间[0,0]以及postorder中下一次建树的根20,[0,0]中根本就找不到创建左子树的根20,那么就出错了。
然后根据在左右区间找到的根然后再建树,再递归。
实现代码:

//代码说起来容易写起来难!
class Solution {
public:
    TreeNode*_buildTree(vector<int>& inorder, vector<int>& postorder,
    int &posti,int inbegin,int inend)
	//posti是标记当前的走到postorder的什么位置了,
	//一定要加引用,因为左子树/右子树每创建一个结点
	//都必须消耗postorder的一个节点。
    //inbegin和inend分别是左右区间
    {
        if(inbegin>inend)
        {
            return nullptr;
        }

        TreeNode*root=new TreeNode(postorder[posti]);//先建树
		
		//在inorder中根据postorder找根所在的位置,
		//根据这个根的位置才能划分左右区间
		
        int root_in_inorder=inbegin;
        while(inorder[root_in_inorder]!=postorder[posti])
        //当有一个结点的时候,提前posti--会导致越界
        {
            root_in_inorder++;
        }
        
        //上面工作都做好了,posti--
        posti--;
        
        root->right=_buildTree(inorder,postorder,posti,root_in_inorder+1,inend);

        root->left=_buildTree(inorder,postorder,posti,inbegin,root_in_inorder-1);

        return root;
    }
    

    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        int postend=postorder.size()-1;//后序遍历的最后一个元素的下标
		
        return _buildTree(inorder,postorder,postend,0,inorder.size()-1);
    }
};

根据一棵树的前序遍历与中序遍历构造二叉树

题目链接
思路:
与前一题类似但也有不同之处。
根据前序遍历从前往后确定根,然后根据中序遍历确定左右区间,前序的话那就应该先建右子树,在建左子树,然后注意prei也就是记录前序遍历的坐标,一定要加引用,因为左子树/右子树每创建一个结点,都必须消耗postorder的一个节点。
实现代码:

class Solution {
public:
    TreeNode* _buildTree(vector<int> & preorder,vector<int> &inorder,
        int & prei,int inbegin,int inend)
    {
        if(inbegin>inend)
        {
            return nullptr;
        }
		
		//在inorder中根据preorder找根所在的位置,
		//根据这个根的位置才能划分左右区间
        int rooti=inbegin;
        while(rooti<=inend)
        {
            if(inorder[rooti]==preorder[prei])
            break;

            ++rooti;
        }

        TreeNode *root=new TreeNode(preorder[prei]);
        prei++;
        
        root->left=_buildTree(preorder,inorder,prei,inbegin,rooti-1);
        root->right=_buildTree(preorder,inorder,prei,rooti+1,inend);
        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int pi=0;//从前序遍历的第一个元素开始确定根的位置
        return _buildTree(preorder,inorder,pi,0,inorder.size()-1);
    }
};

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

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

相关文章

Python 之 Matplotlib 散点图、箱线图和词云图

文章目录一、散点图1. scatter() 函数2. 设置图标大小3. 自定义点的颜色和透明度4. 可以选择不同的颜色条&#xff0c;配合 cmap 参数5. cmap 的分类5.1 Sequential colormaps&#xff1a;连续化色图5.2 Diverging colormaps&#xff1a;两端发散的色图 .5.3 Qualitative color…

Python获取zabbix问题触发器

背景&#xff1a;阿里云的ECS服务器因为阿里云升级插件&#xff0c;导致安全防护程序重启&#xff0c;产生不同的端口。导致低自动发现注册的端口 大量报警。 解决&#xff1a;杀掉关于因为非业务 变更的端口检测的触发器。 相关文档&#xff1a; Zabbix监控之主机端口监控自…

3. 投票 案例项目(合集)

3.投票-1创建项目和子应用 创建项目 命令$ python django-admin startproject mysite 目录结构mysite/ # 项目容器、可任意命名manage.py # 命令行工具mysite/ # 纯 Python 包 # 你引用任何东西都要用到它__init__.py # 空文件 告诉Python这…

面试官让你说说react状态管理?

hooks 为什么不能放在条件判断里 以 setState 为例&#xff0c;在 react 内部&#xff0c;每个组件(Fiber)的 hooks 都是以链表的形式存在 memoizeState 属性中 update 阶段&#xff0c;每次调用 setState&#xff0c;链表就会执行 next 向后移动一步。如果将 setState 写在条…

7-Zip压缩文件如何设置和清除密码?

7-zip拥有极高的压缩比&#xff0c;压缩比要比普通ZIP文件高30-50%&#xff0c;也是很多人选用的压缩格式。和其他压缩文件一样&#xff0c;7-Zip也可以设置密码保护&#xff0c;今天就来说说如何设置和清除7-Zip压缩包的密码。 首先&#xff0c;我们可以通过软件应用商店直接…

代码随想录算法训练营第三十四天 | 860.柠檬水找零,406.根据身高重建队列,452. 用最少数量的箭引爆气球

一、参考资料柠檬水找零https://programmercarl.com/0860.%E6%9F%A0%E6%AA%AC%E6%B0%B4%E6%89%BE%E9%9B%B6.html 根据身高重建队列 https://programmercarl.com/0406.%E6%A0%B9%E6%8D%AE%E8%BA%AB%E9%AB%98%E9%87%8D%E5%BB%BA%E9%98%9F%E5%88%97.html 用最少数量的箭引爆气球ht…

【Redis】Redis 哈希 Hash 键值对集合操作 ( 哈希 Hash 键值对集合简介 | 查询操作 | 增加操作 | 修改操作 )

文章目录一、哈希 Hash 键值对集合二、查询操作1、Redis 中查询 Hash 键值对数据2、查询 Hash 键是否存在3、查询 Hash 中所有的键 Field4、查询 Hash 中所有的值三、增加操作1、Redis 中插入 Hash 键值对数据2、批量插入 Hash 键值对数据四、修改操作1、Hash 中 Field 键对应值…

2|数据挖掘|聚类分析|k-means/k-均值算法

k-means算法k-means算法&#xff0c;也被称为k-平均或k-均值&#xff0c;是一种得到最广泛应用的聚类算法。算法首先随机选择k个对象&#xff0c;每个对象初始地代表了一个簇的平均值或中心。对剩余的每个对象根据其与各个簇中心的距离&#xff0c;将它赋给最近的簇。然后重新计…

XSS-labs-master

XSS 经典14关这边先说一下常用的弹窗手法<script>alert(1)</script> <script>confirm(1)</script> <script>alert(1)</script> <script>alert(/1/zyl)</script> <script>alert(document.cookie)</script> <scr…

Framework学习之旅:Zygote进程

概述 在Android系统中&#xff0c;DVM(Dalvik 虚拟机和ART、应用程序进程以及运行系统的关键服务SystemServer进程都是由Zygote进程来创建的。通过fork&#xff08;复制进程&#xff09;的形式来创建应用程进程和SystemServer进程&#xff0c;由于Zygote进程在启动时会创建DVM…

目标检测综述(一份全的自制PPT): 涵盖各种模型简介对比,适合入门和了解目标检测现状

[TOC](目标检测综述(一份全的自制PPT): 涵盖各种模型简介对比&#xff0c;适合入门和了解目标检测现状) 注&#xff1a;本文仅供学习&#xff0c;未经同意勿转。分享的PPT请勿二次传播&#xff0c;或者用于其他商用途径。若使用本文PPT请注明来源&#xff0c;感谢配合 前言&…

全网超详细的下载与安装VMware虚拟机以及为什么要安装VMware虚拟机

文章目录1. 文章引言2. 下载VMware3. 安装VMware1. 文章引言 我们使用最多的系统是windows系统&#xff0c;因为&#xff0c;国内电脑厂商的操作系统(os)基本是windows系统&#xff0c;比如华为、联想、华硕等电脑。 但线上的服务器大多是Linux系统&#xff0c;而我们经常使用…

numpy 中常用的数据保存、fmt多个参数

在经常性读取大量的数值文件时(比如深度学习训练数据),可以考虑现将数据存储为Numpy格式,然后直接使用Numpy去读取,速度相比为转化前快很多 一、保存为二进制文件(.npy/.npz) &#xff08;1&#xff09;numpy.save(file, arr, allow_pickleTrue, fix_importsTrue) file:文件名…

基于微信小程序的生活日用品交易平台 的设计与实现

基于微信小程序的生活日用品交易平台 的设计与实现 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一…

【信息化知识】

信息化知识 信息化 政务内网需要副省级以上 数据是信息的载体&#xff0c;信息的载体不仅仅只是数据 控制论创始人维纳及信息论的奠基者香农对信息的定义&#xff1a;信息是事物运动状态和状态变化的自我表述 信息化的主体是全体社会成员 信息的质量属性&#xff1a;可验证…

Datawhale统计学习方法打卡Task02

学习教材《统计学习方法&#xff08;第二版&#xff09;》李航 学习内容&#xff1a;第1章 统计学习及监督学习概论 第2章 感知机 感知机&#xff08;perceptron&#xff09;是二类分类的线性分类模型。其输入为实例的特征向量&#xff0c;输出为实例的类别&#xff0c;取1和…

seata源码-全局事务提交 服务端源码

前面的博客中&#xff0c;我们介绍了&#xff0c;发起全局事务时&#xff0c;是如何进行全局事务提交的&#xff0c;这篇博客&#xff0c;主要记录&#xff0c;在seata分布式事务中&#xff0c;全局事务提交的时候&#xff0c;服务端是如何进行处理的 发起全局事务提交操作 事…

时间复杂度(超详解+例题)

全文目录引言如何衡量一个算法的好坏时间复杂度时间复杂度的定义时间复杂度的大O表示法实例test1test2test3test4test5总结引言 如何衡量一个算法的好坏 我们在写算法的时候&#xff0c;对于实现同样的作用的不同算法&#xff0c;我们如何判断这个算法的好坏呢&#xff1f; …

微前端知识点汇总

1、微前端的实现方案 基于 qiankun 的微前端实践 微前端&#xff08;Micro-Frontends&#xff09;是一种类似于微服务的架构&#xff0c;它将微服务的理念应用于浏览器端&#xff0c;即将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。 微前端目标直指巨石…

【Kubernetes】【十一】Pod详解 Pod的生命周期

Pod生命周期 我们一般将pod对象从创建至终的这段时间范围称为pod的生命周期&#xff0c;它主要包含下面的过程&#xff1a; pod创建过程 运行初始化容器&#xff08;init container&#xff09;过程 运行主容器&#xff08;main container&#xff09; 容器启动后钩子&#…