二叉树进阶

news2024/9/26 1:23:33

博主的博客主页:CSND博客
Gitee主页:博主的Gitee
博主的稀土掘金:稀土掘金主页
博主的b站账号:程序员乐
公众号——《小白技术圈》,回复关键字:学习资料。小白学习的电子书籍都在这。

在这里插入图片描述


目录

  • 根据二叉树创建字符串
  • 二叉树的层序遍历
  • 二叉树的最近公共祖先
  • 二叉搜索树与双向链表
  • 从前序与中序遍历序列构造二叉树
  • 从中序与后序遍历序列构造二叉树


根据二叉树创建字符串

题目的意思就是前序遍历这个二叉树,遍历的结果是字符串的形式,该到题目的主要问题就是小括号的问题() 的问题。

  • 我们写这个题目还是要用到递归的思想:
  1. 处理当前逻辑:如果节点不为空,把该值转成字符插入到字符串中;如果为空,就返回空字符串
  2. 处理子树:对于子树我们要考虑括号的问题,处理号括号问题,子树我们也可以看出一个树,所以直接把子树遍历的结果加到字符串就可以了。
  • 什么时候加小括号呢?

左子树什么加括号?——左子树不为空的时候,一定要加;左子树为空的时候,右子树不为空的时候,一定要加括号

右子树什么时候加括号呢?——右子树不为空就加

  1. 返回遍历完成的字符串
class Solution {
public:
    string tree2str(TreeNode* root) {
        string str;
        //当前逻辑
        if(root)
        str+=to_string(root->val);
        else
        return string();
		//左树
        if(root->left||root->right)
        {
            str+='(';
            str+=tree2str(root->left);
            str+=')';
        }
        //右树
        if(root->right)
        {
            str+='(';
            str+=tree2str(root->right);
            str+=')';
        }
        return str;
    }
};

我们这样写虽然可以,但是要注意到,每次返回的时候都有string 的拷贝,这个代价是非常大的,所以我们可以优化一下。我们写一个子函数,然后用引用返回。就可以减少拷贝了。因为传的是引用,所以不需要在返回字符串了,因为直接就添加到字符串中去了。

class Solution {
    void f(string& str,TreeNode* root)
    {
        if(root)
        str+=to_string(root->val);
        else
        return ;
 		//左树
        if(root->left||root->right)
        {
            str+='(';
            f(str,root->left);
            str+=')';
        }
        //右树
        if(root->right)
        {
            str+='(';
            f(str,root->right);
            str+=')';
        }
        
    }
public:
    string tree2str(TreeNode* root) {
        string ret;

        f(ret,root);
        return ret;
    }
};

二叉树的层序遍历

层序遍历我们会的,那就是用一个队列储存每一层的节点,当出队列的同时,把该节点的左右孩子节点也入队列。
但是本题目与我们之前做的题目有点稍微的不同,就是我们返回的是一个二维数组,每一层的元素构成一维数组存在二维数组中。

  • 怎么解决这个问题呢?

用一个值去记录每一层节点的数目,出队列的时候,把节点数加一,当节点数为0的时候,说明该层节点遍历完成;下一层的节点的数目就是队列元素的个数。

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

        if(root)
        q.push(root);
        vector<int> v;
        while(!q.empty())
        {
            TreeNode* cur=q.front();
            q.pop();
            v.push_back(cur->val);
            sum--;

            if(cur->left)
            q.push(cur->left);
            if(cur->right)
            q.push(cur->right);

            if(sum==0)
            {
                sum=q.size();
                vv.push_back(v);
                v.clear();
            }
        }
        return vv;
    }
};

二叉树的最近公共祖先

这道题目我们可以用交叉链表的思想去做,我们把每个节点所在的路径找出来,两个路径相交的第一个节点就是他的最近公共祖先。对于该路径我们用栈进行储存下来。我们用中序遍历的方式去找路径。

  • 找路径的过程
  1. 如果当前节点不是要查找的节点,去找左树,直到查找到空的时候还没有找到,那就删除左树;去找右树,找到了就是该节点,找不到把该节点从栈中删除,在从栈顶的左子树开始查找。
class Solution { 
    bool Find(TreeNode* root,TreeNode* airm,stack<TreeNode*>& st)
    {
        st.push(root);
        if(root==nullptr)
            return false;
        if(root==airm)
        {
            return true;
        }

        if(!Find(root->left,airm,st))
        {
            st.pop();
            root=st.top();
        }
        else
            return true;
        if(!Find(root->right,airm,st))
        {
            st.pop();
            root=st.top();
        }
        else
            return true;

        return false;

    }
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        stack<TreeNode*> pst,qst;
        Find(root, p,pst);
        Find(root,q,qst);

        int i=pst.size()>qst.size()?pst.size()-qst.size():qst.size()-pst.size();
        while(i--)
        {
            if(pst.size()>qst.size())
            pst.pop();
            else
            qst.pop();
        }
        while(qst.top()!=pst.top())
        {
            pst.pop();
            qst.pop();
        }
        return pst.top();
    }
};
  • 另一种方法

去找那两个节点在哪里——是左子树还是右子树。
如果两个节点一个在左子树,另一个在右子树,那么最近公共祖先就是根节点。
如果两个都在同一个子树里面,那么就可以拆分成一个子问题,把子树看成一个树。
特别注意的是,当其中一个节点是该树的根节点的时候,那个该最近公共祖先就是这样该节点。

class Solution {
    bool Find(TreeNode* root,TreeNode* cur)
    {
        if(root==nullptr)
        return false;

        if(root==cur)
        return true;
        
        return Find(root->left,cur)||Find(root->right,cur);
    }
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root==p||root==q)
        return root;

        bool p_left=false,p_right=false;
        bool q_left=false,q_right=false;


        //确定在哪个子树
        if(!Find(root->left,p))
        p_right=true;
        else
        p_left=true;

        if(!Find(root->left,q))
        q_right=true;
        else
        q_left=true;

        if((p_left&&q_right)||(p_right&&q_left))
        return root;
        else if(p_left&&q_left)
        return lowestCommonAncestor(root->left,p,q);
        else if(p_right&&q_right)
        return lowestCommonAncestor(root->right,p,q);
        else
        return nullptr;
    }
};

二叉搜索树与双向链表

把一个二叉树变成一个有序的双向链表,首先有序是很简单的,因为二叉搜索树的中序遍历就是有序的,那么把二叉树进行中序遍历,然后改变节点的指向。
我们用两个指针,一个指针cur指向当前节点的位置,另一个指针pre指向中序遍历过程中当前节点的上一个节点(该节点要设成引用,因为要保证该节点在递归过程中是不变的)。
cur->left=pre,pre->right=cur,然后pre要到当前cur的位置。

class Solution {
	void inorder(TreeNode* root,TreeNode* & pre)
	{
		if(root==nullptr)
		return ;
		inorder(root->left, pre);
		root->left=pre;
		if(pre)
		{
			pre->right=root;	
		}
		pre=root;

		inorder(root->right, pre);
	}
public:
    TreeNode* Convert(TreeNode* pRootOfTree) {
		if(!pRootOfTree)
		return nullptr;
        TreeNode* pre=nullptr;
		TreeNode* root=pRootOfTree;
		while(root->left)
		root=root->left;
		inorder(pRootOfTree,pre);
		return root;
    }
};

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

前序遍历是确定了根节点,中序遍历把根节点分成左右子树。
对于该到题目,我们把前序遍历的每一个元素看成一个根节点,然后利用中序遍历把左右子树确定,而左右子树又可以用该方法确定——子树递归即可。

class Solution {
    TreeNode* create(vector<int>& preorder,vector<int>& inorder,int& i,int L,int R)
    {
        if(L>R||L<0||R<0)
        return nullptr;

        TreeNode* root=new TreeNode(preorder[i]);

        int mid;
        for(mid=L;mid<=R;mid++)
        {
            if(preorder[i]==inorder[mid])
            break;
        }
        i++;

        root->left=create(preorder,inorder,i,L,mid-1);
        root->right=create(preorder,inorder,i,mid+1,R);
        return root;
    }
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int i=0;
        return create(preorder,inorder,i,0,preorder.size()-1);
    }
};

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

该道题目和上一道题目差不多,只不过后序遍历的最后访问根节点。所以我们只需要把上道题目的遍历逆过来就行。注意:该题目先处理右树,在处理左树,因为后序遍历从后往左为:根,右,左。

class Solution {
    TreeNode* create(vector<int>& postorder,vector<int>& inorder,int & i,int L,int R)
    {
        if(L>R||L<0||R<0)
        return nullptr;

        TreeNode* root=new TreeNode(postorder[i]);

        int mid;
        for(mid=L;mid<=R;mid++)
        {
            if(postorder[i]==inorder[mid])
            break;
        }
        i--;

        root->right=create(postorder,inorder,i,mid+1,R);
        root->left=create(postorder,inorder,i,L,mid-1);
        return root;
    }
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        int i=inorder.size()-1;
        return create(postorder,inorder,i,0,inorder.size()-1);
    }
};

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

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

相关文章

基于java+springmvc+mybatis+vue+mysql的协同过滤算法的电影推荐系统

项目介绍 基于协同过滤算法的电影推荐系统利用网络沟通、计算机信息存储管理&#xff0c;有着与传统的方式所无法替代的优点。比如计算检索速度特别快、可靠性特别高、存储容量特别大、保密性特别好、可保存时间特别长、成本特别低等。在工作效率上&#xff0c;能够得到极大地…

Hive自定义UDF函数

以下基于hive 3.1.2版本 Hive中自定义UDF函数&#xff0c;有两种实现方式&#xff0c;一是通过继承org.apache.hadoop.hive.ql.exec.UDF类实现&#xff0c;二是通过继承org.apache.hadoop.hive.ql.udf.generic.GenericUDF类实现。 无论是哪种方式&#xff0c;实现步骤都是&…

网上超市系统

开发工具(eclipse/idea/vscode等)&#xff1a; 数据库(sqlite/mysql/sqlserver等)&#xff1a; 功能模块(请用文字描述&#xff0c;至少200字)&#xff1a; 研究内容&#xff1a;设计开发简单购网上超市系统&#xff0c;采用Java语言&#xff0c;使用ySQL数据库&#xff0c; 实…

毕业设计 单片机家用燃气可视化实时监控报警仪 - 物联网 嵌入式 stm32

文章目录0 前言1 简介2 主要器件3 实现效果4 设计原理4.1 硬件部分4.2 软件部分5 部分核心代码6 最后0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新和亮点&#xff0c;往往达不到毕业答辩的要求&#xff0c;这两…

SAP ABAP 开发管理 代码内存标记 位置使用清单(Mark of memory id)

SAP ABAP 开发管理 代码内存标记 位置使用清单&#xff08;Mark of memory id&#xff09; 引言&#xff1a; 代码内存标记&#xff08;Mark of memory id&#xff09;是我开发中对 ABAP MEMORY ID 使用管理的一种方法&#xff0c;他能有效保障使用了 ABAP MEMORY ID 程序的可…

25岁从运维转向软件开发是选择Python还是Java

25岁的年龄不大&#xff0c;若是有扎实的基础&#xff0c;后期转转向软件开发是个不错的选择&#xff0c;Python是目前最火的编程语言&#xff0c;python作为人工智能的主要编程语言也有着不错的发展前景。 关于编程语言的选择&#xff0c;如果从就业的角度出发应该重点考虑一…

[附源码]Nodejs计算机毕业设计基于框架的校园爱心公益平台的设计与实现Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

Mechatrolink III转EtherCAT网关模块解决方案

概述 工业以太网在工业控制领域越来越流行&#xff0c;协议种类较多&#xff0c;例如Mechatrolink III、EtherCAT、Powerlink、Profinet、EtherNet/IP等等&#xff0c;在数控加工领域主流的协议有Mechatrolink III、EtherCAT。但是各种协议之间很难通信协作。 安川电机的Mech…

CPOFDM-16QAM性能仿真,输出接收端的星座图

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 CP-OFDM&#xff08;Cyclic Prefix Orthogonal Frequency Division Multiplexing&#xff0c;循环前缀正交频分复用&#xff09;通信系统采用多个正交子载波&#xff08;Orthogonalsub-Carrier&a…

非科班出身零基础能学好编程吗

近几年IT行业越来越火热&#xff0c;有很多人想转行跨界进入这个行业&#xff0c;那么作为初学者的你&#xff0c;是不是也很困惑&#xff0c;0基础非科班出身能学好编程吗&#xff1f; 编程是一个技术活&#xff0c;没有专业知识想进入这个行业是行不通的&#xff0c;这也决定…

Go工程化项目布局

如果你尝试学习Go&#xff0c;或者你正在为自己建立一个Poc或者一个玩具项目&#xff0c;这个项目布局是没有啥必要的&#xff0c;从一些简单的事情开始&#xff08;一个main文件绰绰有余&#xff09;。当有更多的人参与这个项目的时候&#xff0c;你讲需要更多的结构&#xff…

基于springboot超市进销存管理系统(Java毕业设计,包含部署文档)

大家好✌&#xff01;我是CZ淡陌。一名专注以理论为基础实战为主的技术博主&#xff0c;将再这里为大家分享优质的实战项目&#xff0c;本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收获&#xff0c;少走一些弯路…

神经网络种类及应用领域,常用的神经网络有哪些

1、神经网络算法的三大类分别是&#xff1f; 神经网络算法的三大类分别是&#xff1a; 1、前馈神经网络&#xff1a; 这是实际应用中最常见的神经网络类型。第一层是输入&#xff0c;最后一层是输出。如果有多个隐藏层&#xff0c;我们称之为“深度”神经网络。他们计算出一…

[附源码]Python计算机毕业设计Django网上鲜花购物系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

一篇文章带你轻松手撕AVL树的构建

1.AVL树介绍 我们知道一般情况下二叉搜索树的查找效率是很高的&#xff0c;但是遇到极端情况下时间复杂度就会来到O(N) 那么为了消除这种极端情况的影响&#xff0c;我们就需要调节这个二叉树通过一些操作转成一颗二叉平衡树&#xff0c;调节完毕就会得到一颗AVL树。 2.AVL树模…

【Linux】第二部分 保姆级手把手教你如何安装Linux

【Linux】第二部分 保姆级手把手教你如何安装Linux 文章目录【Linux】第二部分 保姆级手把手教你如何安装Linux2.保姆级手把手教你如何安装Linux首先下载vmware接下来下载centOS**接着开启虚拟机,对操作系统进行配置**总结2.保姆级手把手教你如何安装Linux 首先下载vmware vm…

阿里云服务器安装oracle11g

1.服务器配置 //linux版本 CentOS-7-x86_64 //oracle版本 linux.x64_11gR2 //查看服务器的CPU个数 cat /proc/cpuinfo | grep physical | sort -n | uniq | wc -l //查看服务器的型号 dmidecode -s system-product-name //查看服务器的cpu型号…

LeetCode题解 14 (3,98) 无重复字符的最长子串,验证二叉搜索树

文章目录无重复字符的最长子串(3)代码解答&#xff1a;验证二叉搜索树(98)代码解答&#xff1a;无重复字符的最长子串(3) 从题目中可以得知我们要找到该字符串中没有重复元素的最长字串,这道题可以采用滑动窗口的方法来解决,今天在这里我们采用新的方法来解决。 首先我们先将该…

转行学Python开发 怎么快速入门

对于很多转行的新手而言&#xff0c;直接参加培训班是最省时省力的事情&#xff0c;参加培训班既不用担心自己学不会&#xff0c;也不用担心遇到不懂的问题时没有人解答&#xff0c;更重要的是培训班理论实践的教学更贴合实际市场需求。 Python目前是IT行业需求量最大的语言&a…

能够让你装逼的10个Python小技巧

列表推导式 你有一个list&#xff1a; bag [1, 2, 3, 4, 5] 现在你想让所有元素翻倍&#xff0c;让它看起来是这个样子&#xff1a; [2, 4, 6, 8, 10] 大多初学者&#xff0c;根据之前语言的经验会大概这样来做 bag [1, 2, 3, 4, 5] for i in range(len(bag)): bag[i] ba…