二叉树OJ题汇总

news2025/1/11 5:05:00

本专栏内容为:leetcode刷题专栏,记录了leetcode热门题目以及重难点题目的详细记录

💓博主csdn个人主页:小小unicorn
⏩专栏分类:Leetcode
🚚代码仓库:小小unicorn的代码仓库🚚
🌹🌹🌹关注我带你学习编程知识

二叉树OJ题汇总

  • 判断二叉树是否为完全二叉树
  • 判断二叉树是否为对称二叉树
  • 判断二叉树是否为平衡二叉树
  • 判断二叉树是否为单值二叉树
  • 判断二叉树是另一棵树的子树
  • 判断两颗二叉树是否相同
    • 解题思路:
  • 二叉树的销毁
  • 二叉树的深度遍历(接口型题目)
    • 前序遍历
    • 中序遍历
    • 后序遍历
  • 左叶子之和
    • 解题思路:
    • 代码解决:
  • 二叉树遍历(牛客)
    • 解题思路:
    • 代码解决:

判断二叉树是否为完全二叉树

思路(借助一个队列):
 1.先把根入队列,然后开始从队头出数据。
 2.出队头的数据,把它的左孩子和右孩子依次从队尾入队列(NULL也入队列)。
 3.重复进行步骤2,直到读取到的队头数据为NULL时停止入队列。
 4.检查队列中剩余数据,若全为NULL,则是完全二叉树;若其中有一个非空的数据,则不是完全二叉树。
在这里插入图片描述

//判断二叉树是否是完全二叉树
bool isCompleteTree(BTNode* root)
{
	Queue q;
	QueueInit(&q);//初始化队列
	if (root != NULL)
		QueuePush(&q, root);
	while (!QueueEmpty(&q))//当队列不为空时,循环继续
	{
		BTNode* front = QueueFront(&q);//读取队头元素
		QueuePop(&q);//删除队头元素
		if (front == NULL)//当读取到空指针时,停止入队操作
			break;
		QueuePush(&q, front->left);//出队元素的左孩子入队列
		QueuePush(&q, front->right);//出队元素的右孩子入队列
	}
	while (!QueueEmpty(&q))//读取队列中剩余的数据
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front != NULL)//若队列中存在非空指针,则不是完全二叉树
		{
			QueueDestroy(&q);//销毁队列
			return false;
		}
	}
	QueueDestroy(&q);//销毁队列
	return true;//若队列中全是空指针,则是完全二叉树
}

判断二叉树是否为对称二叉树

题目来源:101.对称二叉树
题目描述:
给你一个二叉树的根节点 root , 检查它是否轴对称
对称二叉树就是镜像对称。

在这里插入图片描述
要判断某二叉树是否是对称二叉树,则判断其根结点的左子树和右子树是否是镜像对称即可。

因为是镜像对称,所以左子树的遍历方式和右子树的遍历方式是不同的,准确来说,左子树和右子树的遍历是反方向进行的。

//对称二叉树:
bool isSameTree2(BTNode* p, BTNode* q)
{
	//都为空
	if (p == NULL && q == NULL)
	{
		return true;
	}
	//其中一个为空
	if (p == NULL || q == NULL)
	{
		return false;
	}
	//都不为空
	if (p->val != q->val)
	{
		return false;
	}
	return isSameTree2(p->left, q->right) && isSameTree2(p->right, q->left);
}
bool isSymmetric(BTNode* root)
{
	if (root == NULL)
	{
		return true;
	}
	return isSameTree2(root->left, root->right);
}

判断二叉树是否为平衡二叉树

若一棵二叉树的每个结点的左右两个子树的高度差的绝对值不超过1,则称该树为平衡二叉树。
在这里插入图片描述
思路一:
继续拆分子问题:
 1.求出左子树的深度。
 2.求出右子树的深度。
 3.若左子树与右子树的深度差的绝对值不超过1,并且左右子树也是平衡二叉树,则该树是平衡二叉树。

时间复杂度O(N2

//判断二叉树是否是平衡二叉树
bool isBalanced(BTNode* root)
{
	if (root == NULL)//空树是平衡二叉树
		return true;

	int leftDepth = BinaryTreeMaxDepth(root->left);//求左子树的深度
	int rightDepth = BinaryTreeMaxDepth(root->right);//求右子树的深度
	//左右子树高度差的绝对值不超过1 && 其左子树是平衡二叉树 && 其右子树是平衡二叉树
	return abs(leftDepth - rightDepth) < 2 && isBalanced(root->left) && isBalanced(root->right);
}

思路二:
我们可以采用后序遍历:
 1.从叶子结点处开始计算每课子树的高度。(每棵子树的高度 = 左右子树中高度的较大值 + 1)
 2.先判断左子树是否是平衡二叉树。
 3.再判断右子树是否是平衡二叉树。
 4.若左右子树均为平衡二叉树,则返回当前子树的高度给上一层,继续判断上一层的子树是否是平衡二叉树,直到判断到根为止。(若判断过程中,某一棵子树不是平衡二叉树,则该树也就不是平衡二叉树了)

bool _isBalanced(BTNode* root, int* ph)
{
	if (root == NULL)//空树是平衡二叉树
	{
		*ph = 0;//空树返回高度为0
		return true;
	}
	//先判断左子树
	int leftHight = 0;
	if (_isBalanced(root->left, &leftHight) == false)
		return false;
	//再判断右子树
	int rightHight = 0;
	if (_isBalanced(root->right, &rightHight) == false)
		return false;
	//把左右子树的高度中的较大值+1作为当前树的高度返回给上一层
	*ph = Max(leftHight, rightHight) + 1;

	return abs(leftHight - rightHight) < 2;//平衡二叉树的条件
}
//判断二叉树是否是平衡二叉树
bool isBalanced(BTNode* root)
{
	int hight = 0;
	return _isBalanced(root, &hight);
}

判断二叉树是否为单值二叉树

这个题我们可以通过判断二叉树的根与叶子是否相等来解决这个问题,注意要分三种情况:

1.如果是空树,那也是符合情况的,直接返回true。

2.首先满足左子树不为空的条件下,判断左子树的值是否与根相同,相同返回true,不相同返回false.

3.首先满足右子树不为空的条件下,判断右子树的值是否与根相同,相同返回true,不相同返回false.

bool isUnivalTree(BTNode* 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);
}

判断二叉树是另一棵树的子树

题目来源:572.另一颗树的子树

判断 subRoot 是否是二叉树 root 的子树,即检验 root 中是否包含和 subRoot 具有相同结构和结点值的子树,其中 root 和 subRoot 均为非空二叉树。
在这里插入图片描述

思路:
 依次判断以 root 中某一个结点为根的子树是否与subRoot相同。
在这里插入图片描述
发现 root 中的某一个子树与 subRoot 相匹配时,便不再继续比较其他子树,所以图中只会比较到序号2就结束比较。

//比较以root和subRoot为根结点的两棵树是否相等
bool Compare(BTNode* root, BTNode* subRoot)
{
	if (root == NULL&&subRoot == NULL)//均为空树,相等
		return true;
	if (root == NULL || subRoot == NULL)//一个为空另一个不为空,不相等
		return false;
	if (root->val != subRoot->val)//结点的值不同,不相等
		return false;
	//比较两棵树的子结点
	return Compare(root->left, subRoot->left) && Compare(root->right, subRoot->right);
}
//另一个树的子树
bool isSubtree(BTNode* root, BTNode* subRoot)
{
	if (root == NULL)//空树,不可能是与subRoot相同(subRoot非空)
		return false;
	if (Compare(root, subRoot))//以root和subRoot为根,开始比较两棵树是否相同
		return true;
	//判断root的左孩子和右孩子中是否有某一棵子树与subRoot相同
	return isSubtree(root->left, subRoot) || isSubtree(root->right,subRoot);
}

判断两颗二叉树是否相同

题目来源:leetcode100.相同的树
题目描述:
给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

解题思路:

判断两棵二叉树是否相同,也可以将其分解为子问题:
 1.比较两棵树的根是否相同。
 2.比较两根的左子树是否相同。
 3.比较两根的右子树是否相同。

 代码如下:

bool isSameTree(BTNode* p, BTNode* 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);
    
}

二叉树的销毁

二叉树的销毁,与其他数据结构的销毁类似,都是一边遍历一边销毁。但是二叉树需要注意销毁结点的顺序,遍历时我们应该选用后序遍历,也就是说,销毁顺序应该为:左子树->右子树->根。

 我们必须先将左右子树销毁,最后再销毁根结点,若先销毁根结点,那么其左右子树就无法找到,也就无法销毁了。

//二叉树销毁
void BinaryTreeDestroy(BTNode* root)
{
	if (root == NULL)
		return;

	BinaryTreeDestroy(root->left);//销毁左子树
	BinaryTreeDestroy(root->right);//销毁右子树
	free(root);//释放根结点
}

二叉树的深度遍历(接口型题目)

接下来所要说的深度遍历与前面会有所不同,我们前面说到的深度遍历是将一棵二叉树遍历,并将遍历结果打印屏幕上(较简单)。

而下面说到的深度遍历是将一棵二叉树进行遍历,并将遍历结果存储到一个动态开辟的数组中,将数组作为函数返回值进行返回。

思路:
 1.首先计算二叉树中结点的个数,便于确定动态开辟的数组的大小。
 2.遍历二叉树,将遍历结果存储到数组中。
 3.返回数组。

前序遍历

题目来源:144.二叉树的前序遍历
代码:

//求树的结点个数
int TreeSize(BTNode* root)
{
	return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}
//将树中结点的值放入数组
void preorder(BTNode* 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(BTNode* root, int* returnSize)
{
	*returnSize = TreeSize(root);//值的个数等于结点的个数
	int* a = (int*)malloc(sizeof(int)*(*returnSize));
	int i = 0;
	preorder(root, a, &i);//将树中结点的值放入数组
	return arr;
}

中序遍历

题目来源:94.二叉树的中序遍历

//求树的结点个数
int TreeSize(BTNode* root)
{
	return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}
//将树中结点的值放入数组
void inorder(BTNode* root, int* a, int* pi)
{
	if (root == NULL)//根结点为空,直接返回
		return;
	inorder(root->left, a, pi);//先将左子树中结点的值放入数组
	a[(*pi)++] = root->val;//再将根结点的值放入数组
	inorder(root->right, a, pi);//最后将右子树中结点的值放入数组
}
//中序遍历
int* inorderTraversal(BTNode* root, int* returnSize)
{
	*returnSize = TreeSize(root);//值的个数等于结点的个数
	int* a = (int*)malloc(sizeof(int)*(*returnSize));
	int i = 0;
	inorder(root, a, &i);//将树中结点的值放入数组
	return arr;
}

后序遍历

题目来源:145.二叉树的后序遍历

//求树的结点个数
int TreeSize(BTNode* root)
{
	return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}
//将树中结点的值放入数组
void postorder(BTNode* root, int* a, int* pi)
{
	if (root == NULL)//根结点为空,直接返回
		return;
	postorder(root->left, a, pi);//先将左子树中结点的值放入数组
	postorder(root->right, a, pi);//再将右子树中结点的值放入数组
	a[(*pi)++] = root->val;//最后将根结点的值放入数组
}
//后序遍历
int* postorderTraversal(BTNode* root, int* returnSize)
{
	*returnSize = TreeSize(root);//值的个数等于结点的个数
	int* a = (int*)malloc(sizeof(int)*(*returnSize));
	int i = 0;
	postorder(root, a, &i);//将树中结点的值放入数组
	return arr;
}

左叶子之和

题目描述:
给定二叉树的根节点 root ,返回所有左叶子之和。
在这里插入图片描述
题目来源:leetcode404.左叶子之和
牛客:NC248.左叶子之和

解题思路:

在解决这个问题之前,我们首先要知道什么是叶子节点:
叶子节点:当前节点没有左孩子也没有右孩子

具体解题思路如下:
首先:
判断是否为空树,
如果是空树,返回0;
如果不是空树,判断左孩子节点是否为左叶子节点
然后继续遍历左子树和右子树中的孩子节点,并把结果累加起来。

代码解决:

int sumOfLeftLeaves(struct TreeNode* root ) 
{
    if(root==NULL)
    {
        return 0;
    }
    int sum=0;
    if(root->left&&root->left->left==NULL&&root->left->right==NULL)
    {
          sum=root->left->val;
    }

    return sum+sumOfLeftLeaves(root->left)+sumOfLeftLeaves(root->right);
}

结果如下:
在这里插入图片描述
在这里插入图片描述

二叉树遍历(牛客)

题目来源:KY11.二叉树遍历(牛客网)

题目描述:
编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。
输入描述:
输入包括1行字符串,长度不超过100。
输出描述:
可能有多组测试数据,对于每组数据, 输出将输入字符串建立二叉树后中序遍历的序列,每个字符后面都有一个空格。 每个输出结果占一行。
在这里插入图片描述

解题思路:

根据前序遍历所得到的字符串,我们可以很容易地将其对应的二叉树画出来。
在这里插入图片描述
其实很容易发现其中的规律,我们可以依次从字符串读取字符:
 1.若该字符不是#,则我们先构建该值的结点,然后递归构建其左子树和右子树。
 2.若该字符是#,则说明该位置之下不能再构建结点了,返回即可。

构建完树后,使用中序遍历打印二叉树的数据即可。

代码解决:

#include <stdio.h>
#include<stdlib.h>

typedef struct BinaryTreeNode
{
      struct BinaryTreeNode*left;
      struct BinaryTreeNode*right;
      int val;  
}BTNode;

BTNode*GreateTree(char*str,int*pi)
{
    if(str[*pi]=='#')
    {
        (*pi)++;
        return NULL;
    }

    BTNode* root = (BTNode*)malloc(sizeof(BTNode));
    root->val=str[*pi];
    (*pi)++;

    root->left=GreateTree(str, pi);
    root->right=GreateTree(str, pi);
    
     return root;
}

void Inorder(BTNode*root)
{
  if(root==NULL)
  {
    return ;
  }

  Inorder(root->left);
  printf("%c ",root->val);
  Inorder(root->right);

}

int main() 
{
    char str[100];
    scanf("%s",str);

    int i=0;
    BTNode*root=GreateTree(str, &i);
    Inorder(root);
    return 0;
}

测试结果:
在这里插入图片描述

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

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

相关文章

基于B样条的FFD自由变换原理与C++实现

原理&#xff1a; https://blog.csdn.net/shandianfengfan/article/details/113706496 https://blog.csdn.net/qq_38517015/article/details/99724916 https://blog.csdn.net/qq_38517015/article/details/99724916 三次B样条 cubicBSplineFFD .h #pragma once #include &quo…

行业追踪,2023-11-03

自动复盘 2023-11-03 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

QT5通过openss1.1.1实现RSA加密

QT5通过openss1.1.1实现RSA加密 1.查看当前版本的QT依赖哪个版本的openssl #include <QSslSocket> #include <QDebug>qDebug() << QSslSocket::sslLibraryBuildVersionString();控制台输出&#xff1a; "OpenSSL 1.1.1w 11 Sep 2023"可以看到大…

Sulfo-CY3 azide水溶型橘红色荧光染料-星戈瑞

Sulfo-CY3 azide通常被认为是一种红色至近红外光谱区的荧光染料&#xff0c;其发射波长约为560-580纳米左右&#xff0c;而不是橘黄色。它属于Cyanine家族的染料&#xff0c;与其他Cyanine染料一样&#xff0c;其颜色主要是由其分子结构和共轭体系所决定的。 Sulfo-CY3 azide是…

【软件测试】银行项目具体操作流程

项目背景&#xff1a; XXXX银行项目采用的是B/S架构&#xff0c;主要是为了解决银行业务中的柜员、凭证、现金、账务等来自存款、贷款、会计模块的管理。 手工弊端&#xff1a; 1.项目业务复杂度高&#xff0c;回归测试工作量大 2.单个接口功能比较简单&#xff0c;容易实现自…

css:元素居中整理水平居中、垂直居中、水平垂直居中

目录 1、水平居中1.1、行内元素1.2、块级元素 2、垂直居中2.1、单行文字2.2、多行文字2.3、图片垂直居中 3、水平垂直居中参考文章 1、水平居中 1.1、行内元素 行内元素&#xff08;比如文字&#xff0c;span&#xff0c;图片等&#xff09;的水平居中&#xff0c;其父元素中…

GDPU 数据结构 天码行空8

实验八 二叉树的建立及遍历应用 一、【实验目的】 1、掌握二叉树的建立方法 2、掌握二叉树遍历的基本方法&#xff08;前序、中序、后序&#xff09; 3、掌握递归二叉树遍历算法的应用 二、【实验内容】 1.构造一棵二叉树,树的形态如下图(亦见附件)所示&#xff0c;打印出先…

PHP foreach 循环跳过本次循环

$a [[id>1],[id>2],[id>3],[id>4],[id>5],[id>6],[id>7],[id>18],];foreach($a as $v){if($v[id] 5){continue;}$b[] $v[id];}return show_data(,$b); 结果&#xff1a;

Java智慧工地源码(项目端+监管端+数据大屏+APP)

智慧工地系统功能介绍 【智慧工地PC项目端功能总览】 一.项目人员管理 包括&#xff1a;信息管理、信息采集、证件管理、考勤管理、考勤明细、工资管理、现场统计、WIFI教育、工种管理、分包商管理、班组管理、项目管理。 1.信息管理&#xff1a;头像、姓名、性别、身份证、…

“AI换脸诈骗”来势汹汹,三个层面科学应对……

当前&#xff0c;AI技术的广泛应用为社会公众提供了个性化智能化的信息服务&#xff0c;也给网络诈骗带来可乘之机&#xff0c;如不法分子通过面部替换语音合成等方式制作虚假图像、音频、视频仿冒他人身份实施诈骗、侵害消费者合法权益。你认为AI诈骗到底应该如何防范&#xf…

热点报告 | 健身人群抵抗入冬肥,Dirtyfit引领23秋冬潮流?

您是否曾有以下困惑&#xff1f;打开小红书首页推荐&#xff0c;似乎已经被算法教育成了成熟的信息茧房&#xff0c;想要找到下一个热点&#xff0c;又忧虑一叶以障目&#xff1b;看着搜索框热词&#xff0c;又担心无法掌握热词背后的话题命脉&#xff0c;难以在浮光掠影中寻找…

零基础成人英语哪里可以学,柯桥成人英语培训

写作中经常会用到“有利于”的表达&#xff0c;一说到“有利于”&#xff0c;大家最先想到的是 be good for 或者 benefit&#xff0c;很滥&#xff0c;很简单&#xff0c;没有亮点&#xff0c;写作中很难提分。 还有一点&#xff0c;英文写作中很忌讳相同的表达反复出现&…

成集云 | 项目管理系统集成金蝶云星空ERP | 解决方案

方案介绍 项目管理系统是项目的管理者应用专门管理项目的系统软件&#xff0c;在有限的资源约束下&#xff0c;运用系统的观点、方法和理论&#xff0c;对项目涉及的全部工作进行有效地管理。它从项目的投资决策开始到项目结束的全过程进行计划、组织、指挥、协调、控制和评价…

从“别人家的孩子”到创业失败:人生的起伏与自我救赎

在我们的生活中&#xff0c;常常会遇到这样一种人&#xff0c;他们从小优秀&#xff0c;备受瞩目&#xff0c;是那种“别人家的孩子”。他们一路走来&#xff0c;无论是在学业还是工作中&#xff0c;都表现得极为出色&#xff0c;让父母引以为傲。然而&#xff0c;人生并非总是…

CVE-2023-45852:Viessmann Vitogate远程代码执行漏洞复现【附POC】

文章目录 Viessmann Vitogate远程代码执行漏洞(CVE-2023-45852)复现0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 Viessmann Vitogate远程代码执行漏洞(CVE-2023-45852)复现 0x01 前言 免责声明&#xff1a;请…

炫云客户端信用额度如何修改?

现在炫云新注册用户信用额度是100元&#xff0c;但是有人觉得信用额度太高了&#xff0c;想修改信用额度&#xff0c;不知道炫云的信用额度如何修改&#xff0c;今天就教大家如何修改炫云的信用额度。炫云的信用额度在炫云官网和客户端都可以修改。 我们先来看炫云官网如何修改…

跨境电商的地方风味:文化多样性的市场

在数字时代&#xff0c;世界已经变得更加紧密相连&#xff0c;跨越国界的电子商务已成为全球经济的一部分。随着跨境电商的兴起&#xff0c;不仅商品跨国流通&#xff0c;文化也以一种前所未有的方式融合。本文将探讨跨境电商如何推动文化多样性&#xff0c;以及这一市场的前景…

Redis 的另一个集群版之 Codis 集群

文章目录 一、概述二、Codis 组织架构图三、Codis 测试规划四、Codis 安装及配置4.1 安装 Codis4.2 启动 Codis Dashboard4.3 启动 Codis Proxy4.4 启动 Codis Server4.5 启动 Codis FE&#xff08;可选&#xff09; 五、Codis-FE 配置六、测试 Codis 服务 如果您对Redis的了解…

【借力打力】记一次由于堆栈信息不详细的错误排查方法,利用访问日志进行定位问题

【借力打力】记一次由于堆栈信息不详细的错误排查方法&#xff0c;利用访问日志进行定位问题 1&#xff0c;背景2&#xff0c;排查步骤2.1 调用方问题2.2 Nginx手段2.3 运维工具辅助2.4 嵌入tomcat日志记录 3&#xff0c;结果 1&#xff0c;背景 异常信息每隔50分钟显示一次&a…

FFmpeg——使用Canvas录制视频尚存问题的解决方案

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…