链式二叉树高质量OJ—【Leedcode】

news2024/10/6 1:37:38

目录

​编辑

1. 单值二叉树

题目

题目分析

代码实现

不带返回值版本

带返回值版本

递归展开图

2. 相同的树

题目

题目分析

代码实现

3. 对称二叉树

题目

题目分析

代码实现

4. 另外一颗子树

题目

题目分析

代码实现

递归展开图

5. 二叉树的前、中、后序遍历

5.1 二叉树的前序遍历

题目

题目分析

代码实现

注意点


1. 单值二叉树


题目

题目分析

我们在这里首先想到的还是用遍历的想法来实现,把整个数都遍历一遍,看看有没有和val不相等的值,我们这时也可以发现前序遍历比较实用(一来就访问他的根,再访问他的左右孩子)

代码实现分析:

1. 首先在主函数中首先使用if条件判断,判断树的根节点是不是空,是空,就返回true(没有违背单值二叉树的定义)

2. 调用前序遍历,实现前序遍历函数

3. 前序遍历函数中,也要判断父亲节点是不是空,是空就回退到调用左儿子的地方,开始递归调用右孩子,直到遍历完整颗树,都没找到,或者是找到不同的值,一层一层的返回上去.....


易错点1:我们在找到的时候,回退出递归的时候,由于我们回退到的是上一层的左节点,这时即使找到了不同的值,我们还要进行右子树递归,这时就显得非常多余,如何改进呢?

方法:我们发现在前序遍历函数中的if判断条件可以完善一下


易错点2:我们这里先写的是不带返回值的,我们定义了一个全局的flag,先将flag初始化为true,后面如果不是单值二叉树的话,我们又将flag改为false,但是我们提交的时候,会有测试用例跑步过去,其实就是这里定义全局flag的问题,这里假如前一棵树不是单值二叉树(flag=false),但是这时第二次调用单值二叉树的时候,本来输出的结果是true,但是这时却输出false,显然是有问题的,怎么解决呢?

方法:在主函数调用前序遍历函数的前面,每次将flag初始化为true


代码实现

不带返回值版本

bool flag=true;
void PreOrderCompare(struct TreeNode* root ,int val)
{
    
   if(root == NULL || flag ==false)//这里的判断条件flag==false就是(易错点1)说的
    return;

    if(root->val !=val)
    {
        flag=false;
        return;//这里是找到了不同的值,就不要往下递归了,直接开始回退了
    }  
 
    PreOrderCompare(root->left,val);
    PreOrderCompare(root->right,val);

}

bool isUnivalTree(struct TreeNode* root){
      if(root == NULL)
      return true;

      flag=true;//每次调用前序遍历,都要将flag初始化为true(易错点2)
      PreOrderCompare(root,root->val);
      return flag;
}

带返回值版本

这里可以采用数学的交换律

a=b 、b=c ——> a=c

每个节点和自己的左右孩子比较,左右孩子又和自己的左右孩子比较,一直遍历完。。。。

bool isUnivalTree(struct TreeNode* root){
      if(root == NULL)
      return true;

      if(root->left && root->left->val != root->val)
      return false ;  
      
      if(root->right && root->right->val != root->val)
      return false ;

      return isUnivalTree(root->left)
      && isUnivalTree(root->right);
}

递归展开图



2. 相同的树

题目

题目分析

题目是比较两棵树是否相同,也就是看两棵树所有节点的数据是不是相同,这时其实还是采用同时遍历两颗树的方法进行比较,这时就有一下三种情况需要分别处理:

1. 当两颗树都是空的情况,返回true

2. 当两棵树一颗为空,另一颗不为空的时候,就直接返回false

3. 走到这里证明两棵树都不为空,这时比较数据,采用同时递归两棵树的方式进行比较,只有比较到不同的情况,返回false,否则就一直遍历,如果直到遍历完都没又不同的数据,那这两棵树就是相同的了

代码实现

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
      if(p==NULL && q==NULL)
      return true;

      if(p == NULL || q == NULL)
      return false;   
 
      if(p->val != q->val) 
      return false; 
     
    return isSameTree(p->left,q->left)
        && isSameTree(p->right,q->right);
}


3. 对称二叉树

题目

题目分析

题目的意思是判断这颗二叉树是不是对称的,我们发现可以将这颗二叉树分成两个子树进行比较,分别递归比较左子树的left和右子树的right、左子树的right和右子树的letf,如果比较晚了,都一样,那就是对称二叉树

实现步骤:

1. 先判断根节点是不是NULL,是,就返回true

2. 根节点不为NULL,再判断左右孩子节点是不是同时为NULL,如果是,那就返回true

3. 走到这里,那就是左右孩子不同时为空,但是有一个为空,那就返回false

4. 走到这里,那就是左右孩子都不为NULL,那就开始比较节点中的数据,如果不相等,那就返回false

5. 走到这里,那就是左右孩子节点数据相等,就开始递归左孩子节点的left节点和右孩子的right节点、递归左孩子的right节点和右孩子的left节点,两个比较都返回true,这时这颗二叉树才是对称的,否则就不对称

代码实现

bool isSymmetricsSubTree(struct TreeNode* root1,struct TreeNode* root2)
  {
       if(root1 == NULL && root2 ==NULL)
       return true;
       
       if(root1 == NULL || root2 == NULL)
       return false;

       if(root1->val != root2->val)
        return false;

        return isSymmetricsSubTree(root1->left,root2->right)
            &&  isSymmetricsSubTree(root1->right,root2->left); 
  }

bool isSymmetric(struct TreeNode* root){
    if(root == NULL)
    return true;
    
    return isSymmetricsSubTree(root->left, root->right);
}


4. 另外一颗子树


题目

题目分析

题目的意思其实是判断主树中是否有和子树相同的二叉树,这里还是采用遍历的思路

实现步骤:

1. 先判断主树的根节点是不是NULL,是,那就直接返回false

2. 不是NULL,那就开始递归遍历,这是我们可以用这样的方法,把主树的每个节点都和子        树递归比较,也就是前面判断两棵树是不是相同的二叉树的方法(2.相同二叉树)

3. 如果同时遍历比较两棵树,isSameTree返回的是true,那证明两棵树完全一样,如果不一      样,我们这是开始递归isSubtree,把根节点换成左孩子节点和子树进行比较,不相同,那      就开始递归遍历比较右孩子节点和子树,直到将主树的所有节点都和子树进行比较了,          isSameTree都没有返回true,那就是主树里面没有和子树一样的子二叉树

代码实现

注意1:这里的isSubtree返回的是左孩子比较结果 || 右孩子比较结果,也就是左右孩子有一个和子树一样,就返回true

注意2 :这里的isSubtree的返回值,是靠isSameTree带回的


举例:假如遍历比较完了一个根节点的左孩子,这时返回的是false,然后开始遍历这个根节点的右孩子,这是返回的是true,false || true 这时返回的是true

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
      if(p==NULL && q==NULL)
      return true;

      if(p == NULL || q == NULL)
      return false;   
 
      if(p->val != q->val) 
      return false; 
     
    return isSameTree(p->left,q->left)
        && isSameTree(p->right,q->right);
}

bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){

    if(root == NULL)
      return false;
    
    if(isSameTree(root,subRoot))
    return true;

    return isSubtree(root->left,subRoot)
        || isSubtree(root->right,subRoot);

}

递归展开图

以上面的示例画递归展开图



5. 二叉树的前、中、后序遍历


5.1 二叉树的前序遍历

题目

题目分析

题目的意思是遍历这颗二叉树,并把前序遍历的结果放到一个数组里面返回,那这个数组需要是malloc出来的

代码实现步骤:

1. 先判断这颗二叉树的根节点是否为空,为空,直接就return

2. 如果不是NULL,那这时就创建一个子函数,用来返回这个二叉树有多少个节点,然后再动态开辟一个数组用来存数据

3. 再创建一个子函数,用来前序遍历这个二叉树,把数据存储到开辟的空间中,最后返回出去

代码实现

int Treesize (struct TreeNode* root)
{
    return root == NULL ? 0 : Treesize(root->left) + Treesize(root->right) + 1;
} 

void preorder (struct TreeNode* root, int* a , int* pi)
{
    if(root == NULL)
      return ;
    
    a[(*pi)++] = root->val;
    preorder(root->left, a, pi);
    preorder(root->right, a, pi);
}

int* preorderTraversal(struct TreeNode* root, int* returnSize){
    
    *returnSize = Treesize(root);
    int* a=(int*)malloc(*returnSize * sizeof(int));

     int i=0;
     preorder(root, a, &i);

    return a;
}

注意点

上面的代码中,我们传数组a的下标,采用了传指针的方式,为什么呢?(局部变量的原因)


因为在像下面的举例中,我们可以发现,在递归调用存储完3的时候i=2,然后i++,这时的i就变成了3,但是这时遍历3的左右孩子节点的时候发现都为空,这时2的左节点遍历就结束了,就开始右递归,但是本来i为3,但是在返回后,由于i是局部变量,i的值在2递归右孩子节点的函数中是2,但是这时又要存储节点4里的数据,这时前面存储的3就会被2覆盖掉,然后i++,后面就会有一个空的元素,执行就是随机值

觉得文字太多,直接看下面的递归展开图!!!!

 中序和后续遍历的OJ练习题就根据上面讲的前序遍历自己去做下哦!!!



如果觉得文章不错,期待你的一键三连哦,你个鼓励是我创作的动力之源,让我们一起加油,顶峰相见!!!

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

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

相关文章

给电脑重装系统有什么坏处吗

电脑重装系统是解决一些问题的常见方法,但是它也存在一些潜在的坏处。本文将为您详细介绍电脑重装系统的坏处,并提供一些注意事项,帮助您做出明智的决策。 工具/原料: 系统版本:Windows10 品牌型号:惠普…

涂鸦智能发布全球首款Matter+Alexa Built-in涂鸦智选智慧中控屏L

根据Parks Associates今年4月发布的《Next-Generation Smart Home: Building for the Future》显示,41%的美国互联网家庭拥有智能家居设备,越来越多的家庭正在部署全屋智能。 当家中出现越来越多的智能设备时,智慧中控屏,凭借“所…

行业报告 | AIGC应用与实践展望报告:人工智能重塑内容产业的作业模式

原创 | 文 BFT机器人 前言 Introduction 不可否认AIGC的出现似乎已经让大家预见了Al应用的拐点,其创造性与智能性一夜之间刷新了大众认知。但去伪存真,在市场火爆的背后其真正的应用及商业价值几何,更待我们冷静地剖析。 01 概念重生&#…

破解excel单元格保护

EI目录.xlsx 被保护,想查其中期刊,却不能直接复制。 step1.文件后缀改成.rarstep2.360压缩包打开,找到【sheet1.xml】step3.使用记事本打开,删除部分指定代码step4.后缀改回.xlsx 我是用360压缩包可以直接在.rar中 进行修改。 …

生态环境监测好帮手——便携式水污染物监测设备

便携式水污染物监测设备也可以称作便携式水质多参数检测仪 根据生态环境保护需要而专门研发的一款可快速准确测定地表水、地下水、城市污水及工业废水中CODcr、氨氮、总磷、总氮等50余种指标,浓度直读;可广泛用于水厂、食品、化工、冶金、环保及制药行业…

《机器人SLAM导航核心技术与实战》第1季:第5章_机器人主机

视频讲解 【第1季】5.第5章_机器人主机-视频讲解 【第1季】5.1.第5章_机器人主机_X86与ARM主机对比-视频讲解 【第1季】5.2.第5章_机器人主机_ARM主机树莓派3B-视频讲解 【第1季】5.3.第5章_机器人主机_ARM主机RK3399-视频讲解 【第1季】5.4.第5章_机器人主机_ARM主机Jetso…

chatgpt赋能python:Python文件大小函数:了解文件大小的方法和掌握文件操作技巧

Python文件大小函数:了解文件大小的方法和掌握文件操作技巧 文件大小是我们经常需要考虑的一个问题,无论是在计算机存储、文件上传、程序优化等场景中都需要关注。在Python中,我们可以通过文件操作函数来查询文件大小,这篇文章将…

看了两位阿里P10的成长经历,我的认知升华了

两位 P10 大佬的成长经历 相信不少人和我一样,对这些高段位大佬的成长经历有很强的好奇心,想知道他们是如何达到这一步的,这期间有什么关键的选择。这一节我们来看下他们的成长经历,通过了解前辈是如何成长的,可以帮助…

Oracle11G安装说明

Oracle11G安装说明 一、序二、安装安装依赖包基础环境配置安装Oracle 三、配置Oracle 一、序 Oracle和MySQL语法区别:https://blog.csdn.net/lanmuhhh2015/article/details/97763615 Oracle创建用户、角色、授权、建表:https://www.cnblogs.com/roger1…

chatgpt赋能python:Python散点图的颜色设置

Python散点图的颜色设置 什么是散点图? 散点图是一种数据可视化的图表类型。它用于观察两个变量之间的关系。通常,x轴表示一个变量,y轴表示另一个变量。每个点表示一个数据点,它在x和y轴上分别具有对应的值。我们可以通过比较散…

再获数千万元追加投资!宏景智驾B轮总融资已近「5亿元」

5月26日,宏景智驾(Hyperview)宣布获得阿美风险投资(Aramco Ventures)旗下多元化成长基金Prosperity7 Ventures数千万元的追加投资,这也是继2022年2月Prosperity7独家投资宏景智驾超亿元战略融资后又一次投出…

博途1200PLC由丝杠位移速度计算电机转速(moveVel_TO_motorSpeed功能块)

博途PLC 脉冲轴控制,功能块介绍请参看下面文章博客,这篇博客介绍实际组态、编程时的注意事项,仅供参考,受水平和能力所限文中难免有错误和不足之处,欢迎大家评论指出。 博途1200PLC轴控功能块(脉冲轴)_西门子1200可以总线控制伺服么_RXXW_Dor的博客-CSDN博客STRUCT// 轴使…

查询物流不再困难——教您一招批量查询物流信息很管用

在物流行业,快递批量查询高手是一款必备工具。这款软件如同瑞士军刀一样,可以解决许多查询和管理工作中的难题。让我们一起来探讨一下快递批量查询高手的背景、需求、实现方案、功能特点以及应用案例,以了解它的重要性以及实用性。 首先&…

chatgpt赋能python:Python文件所在目录

Python文件所在目录 什么是Python文件所在目录? 在Python编程中,文件所在目录指的是存储Python代码文件的文件夹。该文件夹包含所有Python代码文件,这些文件可以包含函数、类、变量等。 如何查找Python文件所在目录? Python文…

Python类的属性和方法介绍

Python类的属性和方法介绍 本文主要讲python类属性(类变量)、实例属性(实例变量);类方法、静态方法、实例方法。 【定义在类中的变量也称为属性,定义在类中的函数也称为方法。】 这些都是Python面向对象…

Sentinel持久化规则

1.什么是持久化规则 一旦我们重启应用,sentinel规则将消失,生产环境需要将配置规则进行持久化。 2.怎么玩 将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台的流控规则就能看到,只要Nacos…

Day53【动态规划】1143.最长公共子序列、1035.不相交的线、53.最大子序和

1143.最长公共子序列 力扣题目链接/文章讲解 视频讲解 本题最大的难点还是定义 dp 数组 本题和718.最长重复子数组区别在于这里不要求是连续的了,但要有相对顺序 直接动态规划五部曲! 1、确定 dp 数组下标及值含义 dp[i][j]:取 text1…

Hadoop学习---9、Yarn

1、Yarn资源调度器 Yarn是一个资源调度平台,负责为运算程序提供服务器运算资源,相当于一个分布式的操作系统平台,而MapReduce等运算程序则相当于运行在于操作系统之上的应用程序。 1.1 Yarn基础架构 Yarn主要由ResourceManager、NodeManag…

MyCat|Shardingsphere-proxy:jdbc连接MySQL8.0.33的query_cache_size异常解决方案

当前版本:MySQL 8.0.33 ,Mycat-server-1.6.7.6-release-20220524173810-win,apache-shardingsphere-5.3.2-shardingsphere-proxy-bin,jdk 1.8 1. 问题的主要背景 MySQL 8.0.33版本,搭建了主从复制,需要借…

24 VueComponent 的 render

前言 这是最近的碰到的那个 和响应式相关的问题 特定的操作之后响应式对象不“响应“了 引起的一系列的文章 主要记录的是 vue 的相关实现机制 呵呵 理解本文需要 vue 的使用基础, js 的使用基础 测试用例 测试用例如下, 一个简单的 按钮事件的触发 问题的调试 编译…