【Leetcode】二叉树进阶面试题

news2024/9/23 23:31:57

文章目录

  • 二叉树创建字符串
  • 二叉树分层遍历(从前开始)
  • 二叉树分层遍历(从后开始)
  • 二叉树的最近公共祖先
  • 二叉搜索树与双向链表
  • 从前序与中序遍历序列构造二叉树
  • 从中序与后序遍历序列构造二叉树
  • 二叉树的前序遍历(非递归)
  • 二叉树的中序遍历(非递归)
  • 二叉树的后续遍历

二叉树创建字符串

在这里插入图片描述
在这里插入图片描述

思路: 该题需要注意的细节就是当节点的左子树为空,而右子树却不为空的情况,就需要特殊处理,也是需要加上(),而节点的左子树不为空,右子树为空就是不需要加上()if(root->left||root->right)该语句就是实现左子树的字符和(),之后再去处理右子树。

//C++
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;
    }
};

二叉树分层遍历(从前开始)

在这里插入图片描述
在这里插入图片描述

**思路:**创建一个队列,将遍历的数据存入到里面,在创建一个计数器用来记录每层的数据个数。

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*> q;
        vector<vector<int>> vv; 
        int levelsize=0;

        if(root)
        {
            q.push(root);
            levelsize=1;
        }

        while(!q.empty())
        {
            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;
    }
};

二叉树分层遍历(从后开始)

在这里插入图片描述
在这里插入图片描述

**思路:**其实他就和上一个题的思路是一样的,只需要加个翻转就可以了。

class Solution {
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        queue<TreeNode*> q;
        vector<vector<int>> vv; 
        int levelsize=0;

        if(root)
        {
            q.push(root);
            levelsize=1;
        }

        while(!q.empty())
        {
            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();
        }
        reverse(vv.begin(),vv.end());
        return vv;
    }
};

二叉树的最近公共祖先

在这里插入图片描述
在这里插入图片描述

思路:
1、使用三叉链(有父节点)转换为链表相交问题,其中长的一条先走gap。
2、就是进行判断确定一个数在自己的左边,另一个在自己的右边。不在用一边就说明现在的节点就是最近的公共祖先,在同一边就需要继续向下找。

class Solution {
public:

    bool Isintree(TreeNode* root,TreeNode* in)
    {
        if(root==nullptr)
        {
            return false;
        }
        if(root==in)
        {
            return true;
        }
        else
        {
            return Isintree(root->left,in) || Isintree(root->right,in);
        }
    }

    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        
        if(root==nullptr)
        {
            return nullptr;
        }
        if(p==root || q==root)
        {
            return root;
        }

        bool pinleft=Isintree(root->left,p);
        bool pinright=!pinleft;

        bool qinleft=Isintree(root->left,q);
        bool qinright=!qinleft;

        if((pinleft && qinright) || (pinright && qinleft))
        {
            return root;
        }
        else if(pinleft&&qinleft)
        {
            return lowestCommonAncestor(root->left,p,q);
        }
        else
        {
            return lowestCommonAncestor(root->right,p,q);

        }
    }
};

注意: 上面的写法是属于性能较低的,他所用的时间是较长的。时间复杂度是O(N^2)。在他最坏的情况下会出现歪脖子树。也就是确定一次两个数在哪边(递归一边查找,歪脖子树),共要向下递归N次。

思路: 下面的思路就是找到两条路径,用找链表的公共节点的方法来找最近公共节点。需要注意的就是在放入栈之后要进行判断下面没有就要进行出栈。

class Solution {
public:
    bool Getpath(TreeNode* root, TreeNode* g,stack<TreeNode*>& path)
    {
        if(root==nullptr)
        {
            return false;
        }
        path.push(root);//只要不是空就放进来
        if(root==g)
        {
            return true;
        }
        if(Getpath(root->left,g,path))
        {
            return true;
        }

        if(Getpath(root->right,g,path))
        {
            return true;
        }

        path.pop();
        return false;
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        stack<TreeNode*> qpath,ppath;
        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();
    }
};

二叉搜索树与双向链表

在这里插入图片描述

思路: 该题目要求了空间复杂度,要是不要求的话,直接就中序遍历就好了。将节点prev指向空,cur为4的指针,这里要注意成员函数prev的引用,是必须要带上的,不带会影响整个结构的。将cur以递归的路径进行,prev跟上cur之前的节点。通过cur->left=prev,prev->right=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* root=pRootOfTree;
		while(root&&root->left)
		{
			root=root->left;
		}
        return root;
    }
};

从前序与中序遍历序列构造二叉树

在这里插入图片描述

思路: 将中序遍历的数组进行划区域处理,ibegin,iend,iroot,中序前序两个数组比较这进行。具体看代码。

class Solution {
public:
    TreeNode* _buildTree(vector<int>& preorder, vector<int>& inorder,int& prei,int ibegin,int iend)
    {
        if(ibegin>iend)
        {
            return nullptr;
        }
        TreeNode* root=new TreeNode(preorder[prei]);
        int iroot=ibegin;
        while(iroot<=iend)
        {
            if(preorder[prei]==inorder[iroot])
            {
                break;
            }
            else
            {
                iroot++;
            }
        }
        prei++;
        root->left= _buildTree(preorder,inorder,prei,ibegin,iroot-1);
        root->right= _buildTree(preorder,inorder,prei,iroot+1,iend);

        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int prei=0;
        return _buildTree(preorder,inorder,prei,0,preorder.size()-1);
    }
};

从中序与后序遍历序列构造二叉树

在这里插入图片描述

思路: 该题和上一个题的思路是相同的,就是将前序改为后序了,所以就是prei改为从后开始遍历。

class Solution {
public:
    TreeNode* _buildTree(vector<int>& preorder, vector<int>& inorder,int& prei,int ibegin,int iend)
    {
        if(ibegin>iend)
        {
            return nullptr;
        }
        TreeNode* root=new TreeNode(preorder[prei]);
        int iroot=ibegin;
        while(iroot<=iend)
        {
            if(preorder[prei]==inorder[iroot])
            {
                break;
            }
            else
            {
                iroot++;
            }
        }
        prei--;
        root->right= _buildTree(preorder,inorder,prei,iroot+1,iend);
        root->left= _buildTree(preorder,inorder,prei,ibegin,iroot-1);

        return root;
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        int prei=postorder.size()-1;
        return _buildTree(postorder,inorder,prei,0,postorder.size()-1);
    }
};

二叉树的前序遍历(非递归)

在这里插入图片描述

思路: 创建一个数组和一个找,是将树的左子树先进行都先进入数组按顺序。并且将前面进入数组的节点放入栈当中,之后进行对右子树的遍历,这时要将指向右子树的这颗节点进行删除在栈当中。

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> v;
        stack<TreeNode*> s;
        TreeNode* cur=root;
        while(cur || !s.empty())
        {
            while(cur)
            {
                v.push_back(cur->val);
                s.push(cur);
                cur=cur->left;
            }
            TreeNode* top=s.top();
            s.pop();
            cur=top->right;
        }
        return v;
    }
};

二叉树的中序遍历(非递归)

在这里插入图片描述

思路: 它的思路是和上一道题的解法是相同的,就是将pop出的节点,挨个放入数组。

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> v;
        stack<TreeNode*> s;
        TreeNode* cur=root;
        while(cur || !s.empty())
        {
            while(cur)
            {
                s.push(cur);
                cur=cur->left;
            }
            TreeNode* top=s.top();
            v.push_back(top->val);
            s.pop();
            cur=top->right;
        }
        return v;
    }
};

二叉树的后续遍历

在这里插入图片描述

思路: 他与上述的问题差距就是如何让右子树在节点的前面输出,而采用的方法就是创建一个变量,用于判断是否右子树已经在父节点前面输出了。

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> v;
        stack<TreeNode*> s;
        TreeNode* cur=root;
        TreeNode* pre=nullptr;
        while(cur || !s.empty())
        {
            while(cur)
            {
                s.push(cur);
                cur=cur->left;
            }
            TreeNode* top=s.top();
            if(top->right==nullptr || pre==top->right)
            {
                v.push_back(top->val);
                pre=top;
                s.pop();
            }
            else
            {
                cur=top->right;
            }     
        }
        return v;
    }
};

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

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

相关文章

数仓学习---16、可视化报表(Superset)

星光下的赶路人star的个人主页 真正的才智是刚毅的志向 文章目录 1、Superset入门1.1 Superset概述1.2 环境说明 2、Superset安装2.1 安装Python环境2.1.1 安装Miniconda2.1.2 创建Python3.7 环境 2.2 Superset部署2.2.1 安装依赖2.2.2 安装Superset2.2.3 启动Superset2.2.4 Su…

黑客工具大全(网络安全)

1.Nmap 它是网络管理员必用的软件之一&#xff0c;以及用以评估网络系统安全。正如大多数被用于网络安全的工具&#xff0c;nmap 也是不少黑客及骇客&#xff08;又称脚本小子&#xff09;爱用的工具 。 系统管理员可以利用nmap来探测工作环境中未经批准使用的服务器&#xf…

性能如何通过分析后台资源确定瓶颈之磁盘网络

目录 影响性能的因素 磁盘 网络 应用程序-上下文切换 通俗的判断性能的好坏 影响性能的因素 磁盘 %Disk time指所选磁盘驱动器忙于为读或写入请求提供服务所用的时间的百分比。--磁盘的繁忙程度&#xff0c;一般不超过80%。 Disk reads&#xff08;writes&#xff09;b…

Linux-文件管理

1.文件管理概述 1.Bash Shell对文件进行管理 谈到Linux文件管理&#xff0c;首先我们需要了解的就是&#xff0c;我们要对文件做些什么事情&#xff1f; 其实无非就是对一个文件进行、创建、复制、移动、查看、编辑、压缩、查找、删除、等等 例如 : 当我们想修改系统的主机名…

momentjs

年月日 moment(date).format(YYYY-MM-DD) 年月日时间 moment(date).format(YYYY-MM-DD HH-MM-SS) 中文XX月XX日.moment(date).format(MMMDo)

A comprehensive survey on segment anything model for vision and beyond

视觉分割大模型的过去、现在和未来&#xff01;SAM最新综述来了&#xff01;今天自动驾驶之心很荣幸邀请到Garfield来分享视觉SAM分割大模型的最新综述&#xff0c;如果您有相关工作需要分享&#xff0c;https://mp.weixin.qq.com/s/-_QFvxBGzFpAgVGF-t-XRgSegment Anything Mo…

从游戏中理解《重构的时机和方法》(文末送书)

本次推荐的书籍是《重构的时机和方法》&#xff0c;该文是由法国克里斯蒂安克劳森(Christian Clausen) 著作&#xff0c;由郭涛翻译。 重构的时机和方法 寄语译者/本书作者原文作者群英推荐目录自我感受好书哪里来&#x1f929;免费的书籍哪里来&#x1f929; 寄语 作者寄语&a…

Tencent : TBDS

序言 腾讯大数据处理套件&#xff08;Tencent Big Data Suite&#xff0c;TBDS&#xff09;是基于腾讯多年海量数据处理经验&#xff0c;对外提供的可靠、安全、易用的大数据处理平台。您可以借助 TBDS 在公有云、私有云、非云化环境&#xff0c;根据不同数据处理需求选择合适…

栈和队列模拟实现(C++)

文章目录 1.deque的认识1.1介绍2.图析 2.stack模拟实现3.queue模拟实现4.优先级队列模拟实现4.1介绍4.2例题4.3模拟实现 5.测试函数 1.deque的认识 1.1介绍 双端队列 Deque(通常读作“deck”)是double-ended queue的不规则首字母缩写。双端队列是动态长度的序列容器&#xff0…

MySQL多表查询(联合查询、连接查询、子查询)

目录 多表联合查询 联合查询类型 多表连接查询 多表查询的分类 交叉查询&#xff08;笛卡尔积&#xff09; 内连接查询 外连接查询 自连接查询 子查询规则 子查询的分类 子查询的不同结果 EXISTS和NOT EXISTS 子查询应用的不同位置 不同外部语句的子查询应用情况…

spring boot--自动化注入组件原理、内嵌tomcat-1

前言 我们知道开发spring boot项目&#xff0c;在启动类上添加注解SpringBootApplication &#xff0c;然后引入要自动注入的组件依赖&#xff0c;然后现application.properties中加上相应配置就可以自动注入这个组件&#xff0c;那么下面看看自动注入组件是如何实现的 一、S…

Idea 结合docker-compose 发布项目

Idea 结合docker-compose 发布项目 这里写目录标题 Idea 结合docker-compose 发布项目Docker 开启远程访问功能 添加相应端口配置IDEA 链接Docker配置项目 docker-compose.yml本地还需要安装 dockerwin11 安装本地Docker 可能存在问题 Linux内核不是最新 Docker 开启远程访问功…

回文链表——力扣234

文章目录 题目描述法一 将值复制到数组中后用双指针法法二 快慢指针 题目描述 法一 将值复制到数组中后用双指针法 class Solution { public:bool isPalindrome(ListNode* head) {vector<int> v;while(head!NULL){v.emplace_back(head->val);head head->next;}for…

同步、异步、阻塞、非阻塞

一、概念 同步与异步&#xff08;线程间调用&#xff09;的区别&#xff1a;关注的是调用方与被调用方之间的交互方式。同步调用会等待被调用方的结果返回&#xff0c;而异步调用则不会等待结果立即返回&#xff0c;可以通过回调或其他方式获取结果。 阻塞非阻塞&#xff08;…

Nautilus Chain 即将治理通证 NAUT ,生态发展进程加速

独特且优势明显的Nautilus Chain 目前&#xff0c;行业内首个模块化底层Nautilus Chain已经上线主网&#xff0c;并且即将有超过70个应用原生部署在Nautilus Chain上。Nautilus Chain本身是一个以Layer3为定位的区块链系统&#xff0c;其通过Celestia模块化底层来获得DA支持以…

网络安全 HVV蓝队实战之溯源

一、前言 对于攻防演练蓝军的伙伴们来说&#xff0c;最难的技术难题可能就是溯源&#xff0c;尤其在今天代理横行的时代更加难以去溯源攻击者。这里我就举两个溯源来帮助大家梳理溯源过程&#xff0c;一个是只溯源到公司&#xff0c;一个是溯源到个人。 二、溯源实例 2.1IP …

逻辑运算符和短路求值

要了解短路求值就必须先了解什么是逻辑运算符。 逻辑运算符 在了解运算符之前我们必须先知道再JAVA中逻辑运算符的结果是Boolean类型的值 逻辑与“&&” 表达式1 && 表达式2 逻辑与就是只有运算符两边的表达式都为真&#xff0c;结果才为真。 表达式1表达式…

2023潮玩盲盒小程序盲盒商城源码(开源+微信登录+支付对接)

潮玩盲盒星尘潮玩盲盒小程序2023潮玩盲盒小程序盲盒商城源码(开源微信登录支付对接)

209. 长度最小的子数组 中等 1.8K

209. 长度最小的子数组 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a; 原题链接&#xff1a; 209. 长度最小的子数组 https://leetcode.cn/problems/minimum-size-subarray-sum/description/ 完成情况&#xff1a; 解题思路&#xff1…

单表操作、查询

十四、单表的增删改查&#xff08;DML语句&#xff09; CRUD&#xff08;增删改查&#xff09; 为空要用is null is not null &#xff0c;不能写null <>为等于&#xff0c;也可以为is <>不等于 十五、单表复杂查询 select语句及关系运算符 除了数字&#x…