二叉树经典OJ题(2)

news2024/12/27 12:53:35

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

. - 力扣(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);//找p
      dfs(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.coloradmin.cn/o/1595461.html

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

相关文章

PaddleDetection 项目使用说明

PaddleDetection 项目使用说明 PaddleDetection 项目使用说明数据集处理相关模块环境搭建 PaddleDetection 项目使用说明 https://github.com/PaddlePaddle/PaddleDetection/blob/release/2.7/configs/ppyoloe/README_cn.md 自己项目&#xff1a; https://download.csdn.net/d…

ActiveMQ入门案例(queue模式和topic模式)

目录 前言&#xff1a;为什么使用消息中间件&#xff1f; 异步通信 缓冲 解耦 前提&#xff1a;安装并启动activemq 一、点对点&#xff08;point to point&#xff0c; queue&#xff09; 1.1 创建maven项目 1.2 Pom依赖 1.2 JmsProduce 消息生产者 1.3 JmsConsumer…

数据结构课程设计选做(三)---公共钥匙盒(线性表,栈,队列)

2.3.1 题目内容 2.3.1-A [问题描述] 有一个学校的老师共用N个教室&#xff0c;按照规定&#xff0c;所有的钥匙都必须放在公共钥匙盒里&#xff0c;老师不能带钥匙回家。每次老师上课前&#xff0c;都从公共钥匙盒里找到自己上课的教室的钥匙去开门&#xff0c;上完课后&…

FJSP:袋鼠群优化(Kangaroo Swarm Optimization ,KSO)算法求解柔性作业车间调度问题(FJSP),提供MATLAB代码

一、柔性作业车间调度问题 柔性作业车间调度问题&#xff08;Flexible Job Shop Scheduling Problem&#xff0c;FJSP&#xff09;&#xff0c;是一种经典的组合优化问题。在FJSP问题中&#xff0c;有多个作业需要在多个机器上进行加工&#xff0c;每个作业由一系列工序组成&a…

AliyunCTF 2024 - BadApple

文章目录 前言环境搭建漏洞分析漏洞利用参考 前言 本文首发于看雪论坛 https://bbs.kanxue.com/thread-281291.htm 依稀记得那晚被阿里CTF支配的恐惧&#xff0c;今年的阿里CTF笔者就做了一道签到PWN题&#xff0c;当时也是下定决心要学习 jsc pwn 然后复现这道 BadApple 题目…

Paper Reading: MixTeacher:半监督目标检测中利用混合尺度教师挖掘有前景的标签

目录 简介目标/动机工作重点方法训练 实验总结 简介 题目&#xff1a;《MixTeacher: Mining Promising Labels with Mixed Scale Teacher for Semi-Supervised Object Detection》&#xff0c; CVPR 2023 日期&#xff1a;2023.3.16 单位&#xff1a;腾讯&#xff0c;上海交…

Upload-labs(Pass-14 - Pass-16)

Pass-14 &#xff08;图片马&#xff0c;判断文件类型&#xff09; 图片的格式在防护中通常是不会使用后缀进行判断的依据&#xff0c;文件头是文件开头的一段二进制码&#xff0c;不同类型的图片也就会有不同的二进制头。   JPEG (jpg)&#xff0c;文件头&#xff1a;FF D…

【数据挖掘】实验6:初级绘图

实验6&#xff1a;初级绘图 一&#xff1a;实验目的与要求 1&#xff1a;了解R语言中各种图形元素的添加方法&#xff0c;并能够灵活应用这些元素。 2&#xff1a;了解R语言中的各种图形函数&#xff0c;掌握常见图形的绘制方法。 二&#xff1a;实验内容 【直方图】 Eg.1&…

【数据结构】4.List的介绍

目录 1.什么是List 2.常见接口介绍 3.List的使用 1.什么是List 在集合框架中&#xff0c;List是一个接口&#xff0c;继承自Collection。 Collection也是一个接口&#xff0c;该接口中规范了后序容器中常用的一些方法&#xff0c;具体如下&#xff1a; Iterable也是一个接口…

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…

JCR1区局部强化优化器(PRO),原理详解,MATLAB代码免费获取

局部强化优化器&#xff08;Partial Reinforcement Optimizer, PRO&#xff09;代表了进化计算领域的一项创新突破&#xff0c;它是一种全新设计的进化优化算法。该算法的开发灵感来源于心理学中的进化学习和训练理念&#xff0c;特指为一个被称为局部强化效应&#xff08;Part…

特征匹配方法总结梳理

特征匹配在视觉定位、同时定位和映射(SLAM)、图像拼接等方面都有应用 Proj:202404 CMC-R(R.W.--Reference) 南京 河海大学 资助丰富Fundamental Research Funds of China for the Central Universities, Grant/Award Number: B230205048; Jiangsu Higher Education Reform …

day10 | 栈与队列 part-2 (Go) | 20 有效的括号、1047 删除字符串中的所有相邻重复项、150 逆波兰表达式求值

今日任务 20 有效的括号 (题目: . - 力扣&#xff08;LeetCode&#xff09;)1047 删除字符串中的所有相邻重复项 (题目: . - 力扣&#xff08;LeetCode&#xff09;)150 逆波兰表达式求值 (题目: . - 力扣&#xff08;LeetCode&#xff09;) 20 有效的括号 题目: . - 力扣&…

【QT入门】Qt自定义控件与样式设计之鼠标相对、绝对位置、窗口位置、控件位置

往期回顾 【QT入门】 Qt自定义控件与样式设计之QSlider用法及qss-CSDN博客 【QT入门】Qt自定义控件与样式设计之qss的加载方式-CSDN博客 【QT入门】Qt自定义控件与样式设计之控件提升与自定义控件-CSDN博客 【QT入门】Qt自定义控件与样式设计之鼠标相对、绝对位置、窗口位置、控…

YOLOV5 + 双目相机实现三维测距(新版本)

文章目录 YOLOV5 双目相机实现三维测距&#xff08;新版本&#xff09;1. 项目流程2. 测距原理3. 操作步骤和代码解析4. 实时检测5. 训练6. 源码下载 YOLOV5 双目相机实现三维测距&#xff08;新版本&#xff09; 本文主要是对此篇文章做一些改进&#xff0c;以及解释读者在…

MySQL 实例employee表综合查询

目录 表关系图&#xff1a; 例题&#xff1a; 1.查出至少有一个员工的部门。显示部门编号、部门名称、部门位置、部门人数。 2.列出所有员工的姓名及其直接上级的姓名。 3.列出受雇日期早于直接上级的所有员工的编号、姓名、部门名称。 4.列出部门名称和这些部门的员工信…

【进阶六】Python实现SDVRPTW常见求解算法——离散粒子群算法(DPSO)

基于python语言&#xff0c;采用经典离散粒子群算法&#xff08;DPSO&#xff09;对 带硬时间窗的需求拆分车辆路径规划问题&#xff08;SDVRPTW&#xff09; 进行求解。 目录 往期优质资源1. 适用场景2. 代码调整2.1 需求拆分2.2 需求拆分后的服务时长取值问题 3. 求解结果4. …

AI大模型探索之路-提升篇2:一文掌握AI大模型的核心-注意力机制

目录 前言 一、注意力机制简介 二、注意力机制的工作原理 三、注意力机制的变体 1、自注意力&#xff08;Self-Attention&#xff09; 2、双向注意力&#xff08;Bidirectional Attention&#xff09; 3、多头注意力&#xff08;Multi-Head Attention&#xff09; ​4、…

缺失msvcr110.dll要怎么处理?快捷的修复msvcr110.dll方法

当你在使用电脑进行工作或娱乐时&#xff0c;可能会突然遇到一个错误提示&#xff1a;“程序无法启动&#xff0c;因为电脑中缺失msvcr110.dll”。这样的情况不仅会打断你的活动&#xff0c;还可能带来一定程度的不便。面对这个在Windows操作系统中相对常见的问题&#xff0c;其…

执行npm命令一直出现sill idealTree buildDeps怎么办?

一、问题 今天在运行npm时候一直出项sill idealTree buildDeps问题 二、 解决 1、网上查了一下&#xff0c;有网友说先删除用户界面下的npmrc文件&#xff08;注意一定是用户C:\Users\{账户}\下的.npmrc文件下不是nodejs里面&#xff09;&#xff0c;进入到对应目录下&#x…