秃头篇——二叉树进阶算法题

news2024/9/22 20:08:47

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

题目:

思路:这个题很明显需要我们采用二叉树的递归实现(前序遍历),但有一个注意的点:空括号能不能省略的问题,其实我们发现只要左为空,右不为空不能省略括号,剩下情况均可省略。

代码如下:

class Solution {
public:
    string tree2str(TreeNode* root) {
       string str;
       if(root==nullptr)
       {
        return str;
       }
       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;
    }
};

二、二叉树的分层遍历1

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

这个与我们前面的二叉树初阶部分的层序遍历相似,但不同的是,它要把每层数据分别存储成一个二维数组,我们之前的思路是创建两个队列,分别存储该节点及其孩子,等该节点pop掉又会把他们的孩子带进来。

本题思路:创建一个vector<vector<int>>,再创建一个队列以及变量levelsize(记录每层多少个数据),队列存储的是该节点的指针(并不是该节点数据)每次pop掉以后插入到vector变量中,最后把每次的vector 插入到vector<vector<int>>即可。

代码如下:

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> vv;
        queue<TreeNode*>q;
        int levelsize=0;
        if(root)
        {
            q.push(root);
            levelsize=1;
        }
        while(levelsize>0)
        {
           //一层一层出
            vector<int>v;
            while(levelsize--)
            {
                
                TreeNode* front=q.front();
                q.pop();
                v.push_back(front->val);
               //下一层的孩子入队列
                if(front->left)
                {
                   q.push(front->left);
                }
                if(front->right)
                {
                   q.push(front->right);
                }
                
                
            }
            vv.push_back(v);//一层层的插入
            levelsize=q.size();//下一层孩子的节点个数
        }
        return vv;
    }
};

三、二叉树的分层遍历2

题目,与分层遍历1相同,只不过是从底向上遍历。

思路:在二的代码的基础上逆置一下即可,即在return vv前加一个reverse(vv.begin(),vv.end());代码略

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

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

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

比如:5和4的公共祖先是5(自己也可以是祖先),6和4的公共祖先是5,2和8的公共祖先是3,我们能够看出一个规律:除了自己是自己祖先的情况下,剩下的情况一个在祖先的左子树,一个在右子树(只有最近祖先满足这个规律!)

代码如下:

class Solution {
public:
    bool isintree(TreeNode* t, TreeNode* x)//判断是否在子树中
    {
            if(t==nullptr)
            return false;
            return t==x||isintree(t->left,x)||isintree(t->right,x);
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root==nullptr)
        {
          return nullptr;
        }
        if(root==p||root==q)//如果自己就是祖先直接返回即可
        {
            return root;
        }
        bool pinleft=isintree(root->left,p);

        bool pinright = !pinleft;

        bool qinleft=isintree(root->left,q);

        bool qinright = !qinleft;
        if((pinleft&&qinright)||(qinleft&&pinright))//孩子分别在祖先的两侧就是祖先
        {
            return root;
        }
        else if(pinleft&&qinleft)//右子树没有了直接去左子树找形成新的树
            return lowestCommonAncestor(root->left,p,q);
        else
             return lowestCommonAncestor(root->right,p,q);
    }
};

虽然运行时结果都正确,但时间复杂度太高了,不太满足实际。

我们提供另一个思路:如果能求出两个结点到根的路径,那么就可以转换成链表相交问题,两个链表的交点就是公共祖先。我们用一个两个栈即可。代码如下:

class Solution {
public:
     bool getpath(TreeNode* root, TreeNode* x,stack<TreeNode*>&path)
     {
        if(root==nullptr)
        return false;
        //该节点不为空,先入栈再判断
        path.push(root);
        if(root==x)
        {
            return true;
        }
        //子树问题
        if(getpath(root->left,x,path))
        {
            return true;
        }
        if(getpath(root->right,x,path))
        {
            return true;
        }
        //走到这里说明其左右子树都不符合,即出栈递归
        path.pop();
        return false;
     }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        stack <TreeNode*> ppath,qpath;
        getpath(root,p,ppath);
        getpath(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容器中,再把结点的链接关系进行更改即可。在此我们就不用代码演示了。

我们来看下一种思路:依旧是中序遍历二叉树,遍历过程中修改左指针为前驱和右指针为后继指针。记录一个cur和prev,cur为当前中序遍历到的结点,prev为上一个中序遍历的结点,cur->left=prev,但我们不知道cur->right指向哪里,但我们可以让prev->right=cur,也就是说,每个结点的左是再中遍历到当前结点时修改指向前驱,但当前结点的右,是在遍历到下一个结点才可修改后继的。

代码如下:
 

class Solution {
public:
void inorderconvert(TreeNode*cur,TreeNode*&prev)
{
	if(cur==nullptr)
	return ;
	inorderconvert(cur->left,prev);
//中序cur
//左为前驱
	cur->left=prev;
//右为后驱
	if(prev)
	prev->right=cur;
	prev=cur;

	inorderconvert(cur->right,prev);
}
    TreeNode* Convert(TreeNode* root) {
        if(root==nullptr)
		return nullptr;

		TreeNode* prev=nullptr;
		inorderconvert(root, prev);
		TreeNode*head=root;
		while(head->left)
		{
			head=head->left;
		}
//循环链表,头尾相接
		head->left=prev;
		prev->right=head;
		return head;

    }
};

我们发现,以上所有的题目貌似都是用递归的思想去实现代码的,接下来我们来实现一下非递归的思想。

六、二叉树的前、中、后序遍历(非递归)

前序:先访问左路结点,再访问左路结点的右子树,访问右子树要以循环从栈依次取出这些结点,循环子问题的思想访问左路结点的右子树,所以我们需要用一个栈和循环实现。

代码如下:
 

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* top=st.top();
         st.pop();
         //循环访问右子树
         cur=top->right;
       }
       return v;
    }
};

中序:与前序类似,只是我们先入栈不访问,等到左子树走完了以后我们再进行访问,只需要在前序的代码上稍作修改即可

后序:与之前相比麻烦一些,取到一个左路结点时,左子树是否已经访问过了呢?需要我们进行区分,否则程序会进入死循环,如果左路结点的右子树不为空,右子树没有访问,那么上一个访问节点是左子树的根,如果左路节点右子树不为空,右子树已经访问过了,那么上一个访问的是右子树的根。

代码如下:

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
       stack<TreeNode*>st;
       vector<int> v;
       TreeNode*prev=nullptr;
       TreeNode*cur=root;
       while(cur||!st.empty())
       {
        //每次循环代表访问一棵树的开始
        while(cur)
        {
            st.push(cur);
            cur=cur->left;
        }
       //取一个左路节点的右子树出来访问,这时代表左路节点的左子树已经访问过了
        TreeNode* top=st.top();
         //右子树为空或者上一个访问的节点是右子树的根,代表右子树也访问过了。
         if(top->right==nullptr||top->right==prev)
         {
          v.push_back(top->val);
          st.pop();
           prev=top;
         }
         else
         {
         cur=top->right;
          }
    }return v;
};

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

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

相关文章

[JavaEE] 网络初识(网络通信 及 TCP / UDP / IP 封装分用 )

Author&#xff1a;MTingle major:人工智能 --------------------------------------- Build your hopes like a tower! 文章目录 目录 文章目录 一. 网络通信基础 1. 局域网LAN 2. ⼴域⽹WAN 3. IP地址 4. 端口号 二.协议 1. 五元组 2. 协议分层 协议分层的优点: 3. OSI七层协…

OJ在线评测系统 后端开发数据库初始化工作 开发库表 建立数据库索引 Mybatis映射初始化接口开发

后端接口开发库表设计 项目主业务流程的开发 1.用户模块 注册&#xff08;后端已实现&#xff09; 登录&#xff08;后端已实现 前端已实现&#xff09; 2.题目模块 创建题目&#xff08;管理员&#xff09; 删除题目&#xff08;管理员&#xff09; 修改题目&#xff0…

基于SpringBoot+Vue+MySQL的校园一卡通系统

系统展示 用户前台界面 管理员后台界面 系统背景 随着现代社会的快速发展&#xff0c;校园一卡通已成为大学生活中不可或缺的一部分。它不仅承载着校园消费的功能&#xff0c;还集成了学生身份证明、图书馆借阅、门禁系统等多种服务。然而&#xff0c;传统的一卡通管理系统往往…

阿里HPN-用于大型语言模型训练的数据中心网络

阿里巴巴HPN:用于大型语言模型训练的数据中心网络 探索大规模语言模型训练新方法&#xff1a;阿里巴巴HPN数据中心网络论文。 摘要 本文介绍了阿里云用于大型语言模型(LLM)训练的数据中心网络HPN。由于LLM和一般云计算之间的差异(例如&#xff0c;在流量模式和容错性方面)&…

【机器学习】12-决策树1——概念、特征选择

机器学习10-决策树1 学习样本的特征&#xff0c;将样本划分到不同的类别&#xff08;分类问题&#xff09;或预测连续的数值&#xff08;回归问题&#xff09;。 选择特征&#xff0c;划分数据集&#xff0c;划分完成形成模型&#xff08;树结构&#xff09;&#xff0c;一个…

新手必看:一步步教你绑定常见邮箱到第三方应用(如何绑定QQ、163、Hotmail、Gmail等邮箱)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 邮箱绑定 📒📫 QQ邮箱📫 163邮箱📫 Hotmail邮箱📫 Gmail邮箱📫 Yahoo邮箱📫 iCloud邮箱📫 其他邮箱⚓️ 相关链接 ⚓️📖 介绍 📖 你是否曾经为绑定第三方邮箱而感到困惑?你不是一个人!许多人在尝试将QQ邮…

QT创建菜单

增加显示信息

MySQL数据库的增删改查以及基本操作分享

1、登录MySQL数据库 首先找到你安装MySQL数据库的目录&#xff0c;然后在终端打开该目录&#xff0c;输入以下命令 mysql -u root -p然后输入密码就可以登录数据库了&#xff0c;看到如下页面就是登陆成功了 ***注意在终端操纵数据库时所有语句写完之后一定要加 &#xff1…

【线程】线程的同步

本文重点&#xff1a;理解条件变量和生产者消费者模型 同步是在保证数据安全的情况下&#xff0c;让我们的线程访问资源具有一定的顺序性 条件变量cond 当一个线程互斥地访问某个变量时&#xff0c;它可能发现在其它线程改变状态之前&#xff0c;它什么也做不了&#xff0c;…

CSS 选择器的分类与使用要点一

目录 非 VIP 用户可前往公众号进行免费阅读 标签选择器 id 选择器 类选择器 介绍 公共类 CSS 中优先用 class 选择器,慎用 id 选择器 后代选择器 交集选择器 以标签名作为开头 以类名作为开头 连续交集 并集选择器(分组选择器) 通配符* 儿子选择器 >(IE7…

Elasticsearch——介绍、安装与初步使用

目录 1.初识 Elasticsearch1.1.了解 ES1.1.1.Elasticsearch 的作用1.1.2.ELK技术栈1.1.3.Elasticsearch 和 Lucene1.1.4.为什么不是其他搜索技术&#xff1f;1.1.5.总结 1.2.倒排索引1.2.1.正向索引1.2.2.倒排索引1.2.3.正向和倒排 1.3.Elasticsearch 的一些概念1.3.1.文档和字…

基于单片机的智能温控风扇系统的设计

&#xff3b;摘 要&#xff3d; 设计一种基于单片机的智能温控风扇系统&#xff0c;系统由 STC 系列的 51 单片机 、 温度传感器 、 LED 数码管和风扇等模块组成。 本系统具有对外界温度感知以及对感知数据进行分析处理 、 智能调节等功能&#xff0c;避免因温度过高而产生…

【全部更新】2024华为杯数学建模研赛F题思路代码文章全国研究生数学建模-X射线脉冲星光子到达时间建模

截止9.22 14:00 已更新全部文章内容完整求解代码(正版授权) ### https://docs.qq.com/doc/DVVBUREF2SmFhRUl3X射线脉冲星光子到达时间建模 摘要 脉冲星是一类高速自转的中子星&#xff0c;其自转形成规律性脉冲信号&#xff0c;类似于“宇宙中的灯塔”&#xff0c;因此被认为是…

鸿蒙 WebView 如何 Debug

前置&#xff1a; hdc chrome //----------------------------------------------------------------------------------------------- hdc shell cat /proc/net/unix | grep devtools 0: 00000002 0 10000 1 1 81134005 webview_devtools_remote_62479exit执行&…

[001-02-001].第2节:java开发环境搭建

4.1.书籍推荐&#xff1a; 4.2.人机交互方式 1.图形化界面(Graphical User Interface GUI)这种方式简单直观&#xff0c;使用者易于接受&#xff0c;容易上手操作2.命令行方式(Command Line Interface CLI)&#xff1a;需要有一个控制台&#xff0c;输入特定的指令&#xff0c…

828华为云征文|云服务器Flexus X实例|MacOS系统-宝塔部署Nuxt项目

文章目录 1. Flexus云服务器X实例1.1 与Flexus应用服务器L实例相比具备以下优势1.2 服务器的详细配置 2.宝塔部署Nuxt项目2.1 登录实例2.1 宝塔面板 3. Nuxt 项目与部署3.1 Nuxt3.2创建Nuxt项目3.3 部署3.4 部署成功 4.结语 1. Flexus云服务器X实例 华为云的Flexus云服务是为中…

股指期权交易详细基础介绍

股指期权是期权市场中的一种特定类型&#xff0c;其标的资产为股票指数。简而言之&#xff0c;它允许投资者在未来某个特定时间&#xff0c;以预先约定的价格&#xff0c;买入或卖出股票指数的权利。在中国&#xff0c;已上市的股指期权包括上证50、沪深300和中证1000股指期权&…

【C++ Primer Plus习题】17.5

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: #include <iostream> #include <fstream> #include <…

数据库系统基础概述

文章目录 前言一、数据库基础概念 1.数据库系统的组成2.数据模型3.数据库的体系结构二、MySQL数据库 1.了解MySQL2.MySQL的特性3.MySQL的应用场景总结 前言 MySQL数据库是一款完全免费的产品&#xff0c;用户可以直接从网上下载使用&#xff0c;不用花费任何费用。这点对于初学…

react开发环境搭建

文章目录 准备工作创建 React 项目使用 create-react-app 创建 React 项目使用 Vite 创建 React 项目启动项目效果安装出现的情况 react项目文件讲解1. 项目根目录2. 其他可能的目录和文件3. 配置文件 准备工作 Node.js 安装方法&#xff1a; 方式一&#xff1a;使用 NVM 安装…