【数据结构】--二叉树OJ题

本文介绍了多个关于二叉树的LeetCode题目,包括单值二叉树、相同树、对称二叉树、前序遍历、中序遍历、后序遍历、子树判断、最大深度、平衡二叉树和翻转二叉树的解题思路和关键算法。强调了理解递归和多刷题的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

力扣965:单值二叉树

OJ链接

在这里插入图片描述

首先先从第一个节点开始,判断它和它的左右子树相不相等,如果不相等直接就返回false,如果相等递归判断它的左子树和右子树

bool isUnivalTree(struct TreeNode* root){
    if(root == NULL)
        return true;
    //判断和左子树是否相等
    if(root->left && root->val != root->left->val )
        return false;

    //判断和右子树是否相等
    if(root->right && root->val != root->right->val)
        return false;

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

力扣100:相同的树

OJ链接

在这里插入图片描述

有几种情况:

  1. 两个树都为空,相同
  2. 一个为空一个不为空,不相同
  3. 两个数相同位置的节点不相等

判断几种情况后,递归判断两个数同个位置节点是否相同

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
    if(p == NULL && q == NULL)
        return true;
    if(p && q == NULL)
        return false;
    if(q && p == NULL)
        return false;
    if(p->val != q->val)
        return false;

    return isSameTree(p->left,q->left) && isSameTree(q->right,p->right);
}

力扣101:对称二叉树

OJ链接

在这里插入图片描述

由题目可得出要判断这个树是否对称,只需要判断每个节点的左右树是否呈镜像。

所以要用到两个树进行比较,由上图可以看出,根节点的左树(r1)和右树(r2)呈镜像,需要的前提是,r1的左孩子等于r2的右孩子;r1的右孩子等于r2的左孩子,以此类推,只要每个节点的左右树都满足这个条件那么这颗树就对称

//判断左右子树是否对称的接口函数
bool isSame(struct TreeNode* r1, struct TreeNode* r2){
    //如果两个子树都为空,则对称
    if(r1 == NULL && r2 == NULL)
        return true;
    //如果一个为空一个不为空,就不对称
    if(r1 == NULL || r2 == NULL)
        return false;
    //如果两个子树的第一个节点值不一样就不对称
    if(r1 && r2 && r1->val != r2->val)
        return false;

    //递归比较
    return isSame(r1->left,r2->right) && isSame(r1->right,r2->left);
}

bool isSymmetric(struct TreeNode* root){
    return isSame(root->left,root->right);
}

力扣144:二叉树的前序遍历

OJ链接

在这里插入图片描述

利用数组来存放树的每个节点,所以首先开辟一个空间,为了避免空间浪费,可以先调用一个函数算出树的节点个数再开辟

前序遍历,先遍历根节点,再到左孩子,然后右孩子,所以先把根节点放到数组里,递归下去

//计算节点个数
 int TreeSize(struct TreeNode* root)
{
	return root == NULL ? 0 :
		TreeSize(root->left) + TreeSize(root->right) + 1;
}

void Preorder(struct TreeNode* root, int* a, int* i){
    if(root == NULL)
        return;
    
    a[(*i)] = root->val;
    (*i)++;

    Preorder(root->left, a, i);
    Preorder(root->right, a, i);
}

int* preorderTraversal(struct TreeNode* root, int* returnSize){
    int n = TreeSize(root);
    *returnSize = n;

    int* a = (int*)malloc(sizeof(int) * n);
    if(a == NULL)
        return;
    
    int i = 0;
    Preorder(root, a, &i);

    return a;
}

力扣94:二叉树的中序遍历

OJ链接

在这里插入图片描述

和前序的思路一样,不过得先遍历左孩子,所以调换一下顺序

//计算节点个数
 int TreeSize(struct TreeNode* root)
{
	return root == NULL ? 0 :
		TreeSize(root->left) + TreeSize(root->right) + 1;
}

void Preorder(struct TreeNode* root, int* a, int* i){
    if(root == NULL)
        return;
    
    Preorder(root->left, a, i);
    
    a[(*i)] = root->val;
    (*i)++;

    Preorder(root->right, a, i);
}

int* inorderTraversal(struct TreeNode* root, int* returnSize){
    int n = TreeSize(root);
    *returnSize = n;

    int* a = (int*)malloc(sizeof(int) * n);
    if(a == NULL)
        return;
    
    int i = 0;
    Preorder(root, a, &i);

    return a;
}

力扣145:二叉树的后序遍历

OJ链接

在这里插入图片描述

和前序 中序都一样,不过的先遍历左孩子,再到右孩子,最后才是根

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

void Preorder(struct TreeNode* root, int* a, int* i){
    if(root == NULL)
        return;
    
    Preorder(root->left, a, i);
    Preorder(root->right, a, i);

    a[(*i)++] = root->val;
}

int* inorderTraversal(struct TreeNode* root, int* returnSize){
    int n = TreeSize(root);
    *returnSize = n;

    int* a = (int*)malloc(sizeof(int) * n);
    if(a == NULL)
        return;
    
    int i = 0;
    Preorder(root, a, &i);

    return a;
}

力扣572:另一颗树的子树

OJ链接

在这里插入图片描述

判断一棵树是否为另一颗树的子树,其实整体思路很简单,在之前我们已经写出了比较两个数是否相同,所以只需要把root这棵树的每一个节点都看作是一颗新的树,然后跟subRoot这棵树比较,只要有一个相同那就说明subRoot是root的子树

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
    if(p == NULL && q == NULL)
        return true;
    if(p && q == NULL)
        return false;
    if(q && p == NULL)
        return false;
    if(p->val != q->val)
        return false;

    return isSameTree(p->left,q->left) && isSameTree(q->right,p->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);
}

力扣104:二叉树的最大深度

OJ链接

在这里插入图片描述

求最大深度也就求该树的高度,也就是看二叉树有多少层,整体思路可以这样想

除去根节点的一层后,分别求出左子树的高度和右子树的高度,取较大值再加上根节点的一层即可

代码实现需要用到递归,对左右子树分别计算,如果遇到NULL返回0,如果不是累加1

int maxDepth(struct TreeNode* root){
    if(root == NULL)
        return 0;
    //计算左子树
    int left = maxDepth(root->left) + 1;
    //计算右子树
    int right = maxDepth(root->right) + 1;

    //返回较大值
    return left > right ? left : right;
}

力扣110:平衡二叉树

OJ链接

在这里插入图片描述

要判断是否平衡就需要每一个节点都进行判断,如果某一个节点的左右子树高度差大于1,则返回false。利用上面那道题写的求高度,对每个结点的左右子树求高度,计算出高度差进行判断

int maxDepth(struct TreeNode* root){
    if(root == NULL)
        return 0;
    //计算左子树
    int left = maxDepth(root->left) + 1;
    //计算右子树
    int right = maxDepth(root->right) + 1;

    //返回较大值
    return left > right ? left : right;
}

bool isBalanced(struct TreeNode* root){
    //如果树是空树
    if(root == NULL)
        return true;
    
    //递归对每个结点都进行判断
    if(isBalanced(root->right) && isBalanced(root->left) && abs(maxDepth(root->left) - maxDepth(root->right)) <= 1)
        return true;
     
    else
        return false;
}

力扣226:翻转二叉树

OJ链接

在这里插入图片描述

可以看到图中,相对于每一个结点,其左右子树进行了互换

也就是说我们只需要对每一个结点的左右子树的地址进行互换过来即可

//交换每个节点的两个孩子节点地址即可
struct TreeNode* invertTree(struct TreeNode* root){
    if(root == NULL)
        return NULL;
    
    //交换地址
    struct TreeNode* tmp = root->right;
    root->right = root->left;
    root->left = tmp;

    //递归每一个节点
    invertTree(root->left);
    invertTree(root->right);

    return root;
}

牛客:二叉树的遍历

OJ链接

在这里插入图片描述

根据题目描述,可以得到整体思路就是通过前序遍历的顺序先进行还原树,然后再对树进行中序遍历

以例子为例:ABC##DE#G##F###,还原树的结构是

在这里插入图片描述

前序遍历的顺序是,根->左->右

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

//定义二叉树结点结构
typedef char BTDataType;
typedef struct BinaryTreeNode {
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;

//根据字符串创建还原树
BTNode* BinaryTreeCreate(BTDataType* a, int* pi){
    //'#'代表的NULL,所以遇到#号可以直接返回,
    //但要注意pi要往后走一位才可以访问到字符串的下一个字符
    if(a[*pi] == '#'){
        (*pi)++;
        return NULL;
    }
    
    //开辟节点
    BTNode* root = (BTNode*)malloc(sizeof(BTNode));
    if(root == NULL)
        return NULL;
    //将字符赋给节点
    root->data = a[*pi];
    (*pi)++;
    
    //根据前序的顺序,先左再右
    root->left = BinaryTreeCreate(a, pi);
    root->right = BinaryTreeCreate(a, pi);
    
    return root;
}

//中序遍历
void InOrder(BTNode* root) {
	if (root == NULL)
		return;

	InOrder(root->left);

	printf("%c ", root->data);

	InOrder(root->right);
}

int main(){
    char str[101];
    scanf("%s",str);
    int i = 0;
    BTNode* root = BinaryTreeCreate(str,&i);
    
    InOrder(root);
    return 0;
}

总结

对于二叉树而言,难点就在于理解递归
可以画多几遍递归展开图去帮助理解
有事没事就得多刷题,加油
在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值