草庐IT

【深入理解二叉树OJ题】

在肯德基吃麻辣烫 2023-06-23 原文

文章目录

一、单值二叉树

航班直达!

前序遍历的思想。

思路:先判断左右节点是否存在,再判断根分别和左右节点的值是
否相等。

1.如果左子节点存在,但是值不等于根节点的值,返回false
2.如果右子节点存在,但是值不等于根节点的值,返回false

如果相等,递归其左子节点和右子节点。

不拿如果子节点的值等于根节点的值这个条件来判断的原因是:

就算子节点的值和根节点的相等,也不能代表什么,因为还需要判断下一层子节点的值都与它们的根节点的值相等才行,这样才能达到判断整棵树的值都相等的效果。

即:先判断结构,再判断值

注意:如果根节点为空,返回true,特殊情况特殊处理。

//思路:前序遍历的思想,根先与左右比较,如果不同,直接返回假
//再让左子树与左子树的左右子树比较,这样分治下去

bool isUnivalTree(struct TreeNode* root)
{
    //空树返回真,因为最后叶子节点的左右子树都为空
    if(root == NULL)
    {
        return true;
    }

    //两个不能写反了,先判断是否为空再比较数据
    if(root->left!=NULL && root->left->val != root->val)
    {
        return false;
    }

    if(root->right!=NULL && root->right->val != root->val)
    {
        return false;
    }

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

}

二、二叉树最大深度

航班直达!

思路:分别递归根节点的左子节点和右子节点,每次递归一层就计算一层深度,然后比较左右子节点的高度,让大的值+1,(+1是加根节点自己的高度)

//思路:前序遍历的思想+分治算法
//把整棵树看作根左子树右子树组成,先计算左子树的高度和右子树的高度,
//比较之后,大的再加上自己的高度
//左子树又让左子树的左右子树比较高度
int maxDepth(struct TreeNode* root)
{
    if(root == NULL)
    {
        return 0;
    }
    //注意:千万不能写成:
    //return maxDepth(root->left)>maxDepth(root->right)?maxDepth(root->left)+1:maxDepth(root->right)+1;
    //这样写虽然能通过,但是效率大大降低,因为同样的事情重复了好多次
    
    int lheight = maxDepth(root->left);
    int rheight = maxDepth(root->right);
    return lheight>rheight?lheight+1:rheight+1;

}

三、翻转二叉树

航班直达!

思路:后序遍历的思想,先从最底层开始交换:

root->left = right,root->right = left

如果递归到叶子节点了,该叶子节点的左右子树都为NULL,交换它们结果是一样的

所以最底层交换完了,回到上一层,左子树交换完了,到右子树,最后返回根节点即可

//思路:后序遍历的思想,先从最底层开始交换:
//root->left = right,root->right = left
//如果递归到叶子节点了,该叶子节点的左右子树都为NULL,交换它们结果是一样的
//所以最底层交换完了,回到上一层,左子树交换完了,到右子树,最后返回根节点即可
struct TreeNode* invertTree(struct TreeNode* root)
{
    if(root == NULL)
    {
        return NULL;
    }
    struct TreeNode*left = invertTree(root->left);

    struct TreeNode*right = invertTree(root->right);

    root->left = right;
    root->right = left;

    return root;
}

四、检查两棵树是否相同

航班直达!

思路:最好是前序遍历:只要从根节点开始,有一个节点的结构不相同,或者值不相同,都返回假

先判断结构,再判断值

判断值的时候,如果值为真,也没有什么意义,因为还需要不断往下比较

所以应该判断值为假,返回false比较合适

//思路:最好是前序遍历:只要从根节点开始,有一个节点的结构不相同,或者值不相同,都返回假
//先判断结构,再判断值
//判断值的时候,如果值为真,也没有什么意义,因为还需要不断往下比较
//所以应该判断值为假,返回false比较合适
bool isSameTree(struct TreeNode* p, struct TreeNode* q)
{
    //1.先判断结构
    //两个都是空树,返回真
    if(p == NULL && q == NULL)
    {
        return true;
    }
    //来到这里,必有一假,其中一个是空树,返回假
    if(p == NULL || q == NULL)
    {
        return false;
    }
    //2.结构判断完了,判断值
    if(p->val!= q->val )
    {
        return false;
    }
    return isSameTree(p->left,q->left) && isSameTree(p->right,q->right);
}

五、对称二叉树

航班直达!

思路:根节点无需判断,应该写一个函数单独判断两颗子树是否对称的问题

对称问题其实就是判断两颗子树是否相同问题的变形,判断两颗子树是否相同,就是递归两个子树的左和左,右和右,

判断两颗子树是否对称,是递归两个子树的左和右,右和左

先判断结构对称,再判断数据对称

bool isSymmetricalBinaryTree(struct TreeNode* l,struct TreeNode* r)
{
    //两个都为空
    if(!l && !r)
    {
        return true;
    }
    //其中一个为空
    if(l == NULL || r == NULL)
    {
        return false;
    }
    //都不为空
    if(l->val!=r->val)
    {
        return false;
    }

    return isSymmetricalBinaryTree(l->left,r->right) &&isSymmetricalBinaryTree(l->right,r->left); 
    
}
bool isSymmetric(struct TreeNode* root)
{
    //题目说了不是空树
    // if(root == NULL)
    // {
    //     return true;
    // }
    return isSymmetricalBinaryTree(root->left,root->right);
}

六、二叉树遍历

航班直达!

这道题是IO型,需要完全实现输入输出。
思路:按照题目要求,按前序遍历的思想建立一棵树。
然后以中序遍历打印出来,注意:打印完后需要销毁树。

#include <stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef char BTDataType;
struct BTNode
{
    struct BTNode*left;
    struct BTNode*right;
    BTDataType data;
};

struct BTNode* CreatTree(BTDataType*a,int *pi)
{
    //(*pi)++不能放在判断这里++,要放在里面,因为如果a[*pi]不为'#',也一样++了,到下面pi这里就++两次了。
    if(a[(*pi)] =='#')
    {
        (*pi)++;
        return NULL;
    }
    struct BTNode*root = (struct BTNode*)malloc(sizeof(struct BTNode));
    assert(root!=NULL);
    root->data = a[(*pi)++];
    root->left = CreatTree(a,pi);
    root->right = CreatTree(a,pi);
    return root;
}

void InOrder(struct BTNode*root)
{
    if(root == NULL)
    {
        return ;
    }
    InOrder(root->left);
    printf("%c ",root->data);
    InOrder(root->right);
}

void BTDestroy(struct BTNode*root)
{
    if(root == NULL)
    {
        return ;
    }
    BTDestroy(root->left);
    BTDestroy(root->right);
    free(root);
    //置空没效果
    root = NULL;
}

int main() {
    BTDataType a[100];
    scanf("%s",a);
    int i =0;
    struct BTNode*root = CreatTree(a,&i);
    InOrder(root);
    BTDestroy(root);
    root = NULL;
    return 0;

}

有关【深入理解二叉树OJ题】的更多相关文章

  1. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  2. TimeSformer:抛弃CNN的Transformer视频理解框架 - 2

    Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图

  3. ruby - 易于初学者理解的 Ruby 库 - 2

    关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭3年前。Improvethisquestion我正处于学习Ruby的阶段,我想查看一些小型库的源代码以了解它们是如何构建的。我不知道什么是小型图书馆,但希望SO能推荐一些易于理解的图书馆来学习。因此,如果有人知道一两个非常小的库,这是新手Rubyists学习的好例子,请推荐!我想使用Manveru'sInnatelib,因为它试图保持在2000LOC以下,但我还不熟悉其中经常使用的Ruby速记。也许大约100-5

  4. ruby - 无法理解 `puts{}.class` 和 `puts({}.class)` 之间的区别 - 2

    由于匿名block和散列block看起来大致相同。我正在玩它。我做了一些严肃的观察,如下所示:{}.class#=>Hash好的,这很酷。空block被视为Hash。print{}.class#=>NilClassputs{}.class#=>NilClass为什么上面的代码和NilClass一样,下面的代码又显示了Hash?puts({}.class)#Hash#=>nilprint({}.class)#Hash=>nil谁能帮我理解上面发生了什么?我完全不同意@Lindydancer的观点你如何解释下面几行:print{}.class#NilClassprint[].class#A

  5. ruby - 在 Ruby 中实现二叉树 - 2

    我一直在尝试在Ruby中实现BinaryTree类,但我得到了stackleveltoodeep错误,尽管我似乎没有在该特定代码段中使用任何递归:1.classBinaryTree2.includeEnumerable3.4.attr_accessor:value5.6.definitialize(value=nil)7.@value=value8.@left=BinaryTree.new#stackleveltoodeephere9.@right=BinaryTree.new#andhere10.end11.12.defempty?13.(self.value==nil)?true:

  6. ruby - 如何理解 Ruby 中的发送者和接收者? - 2

    我很难理解Ruby中sender和receiver的实际含义。它们一般是什么意思?到目前为止,我只是将它们理解为方法调用和获取其返回值的调用。但是,我知道我的理解还远远不够。谁能给我一个Ruby中发送者和接收者的具体解释? 最佳答案 面向对象中的一个核心概念是消息传递和早期概念化,这在很大程度上借鉴了计算的Actor模型。艾伦·凯(AlanKay)创造了面向对象一词并发明了最早的OO语言之一SmallTalk,他拥有voicedregretatusingatermwhichputthefocusonobjectsinsteadofo

  7. ruby-on-rails - Rails - 理解 application.js 和 application.css - 2

    rails新手。只是想了解\assests目录中的这两个文件。例如,application.js文件有如下行://=requirejquery//=requirejquery_ujs//=require_tree.我理解require_tree。只是将所有JS文件添加到当前目录中。根据上下文,我可以看出requirejquery添加了jQuery库。但是它从哪里得到这些jQuery库呢?我没有在我的Assets文件夹中看到任何jquery.js文件——或者直接在我的整个应用程序中没有看到任何jquery.js文件?同样,我正在按照一些说明安装TwitterBootstrap(http:

  8. ruby - 你如何理解 Ruby 中的这个三元条件? - 2

    我在某些代码中遇到了三元组,但我无法理解条件:str.split(/',\s*'/).mapdo|match|match[0]==?,?match:"somestring"end.join我确实理解我是在某些点上拆分字符串并将总结果转换为数组,然后依次处理数组的每个元素。除此之外,我不知道发生了什么。 最佳答案 一种(稍微)不那么令人困惑的写法是:str.split(/',\s*'/).mapdo|match|ifmatch[0]==?,matchelse"somestring"endend.join我认为多行三元语句很糟糕,尤其是

  9. ruby - 您如何将 S3 理解为 Ruby 中的分层目录结构? - 2

    有没有人成功地将S3存储桶读取为子文件夹?文件夹1--子文件夹2----文件3----文件4--文件1--文件2文件夹2--子文件夹3--文件5--文件6我的任务是读取文件夹1。我希望看到子文件夹2、文件1和文件2,但看不到文件3或文件4。现在,因为我将存储桶键限制为prefix=>'folder1/',你仍然会得到file3和4,因为它们在技术上具有folder1前缀。似乎真正做到这一点的唯一方法是吸收folder1下的所有键,然后使用字符串搜索从结果数组中实际排除file3和file4。有没有人有过这方面的经验?我知道像Transmit和Cyber​​duck这样的FTP风格的S3

  10. 关于yolov5训练时参数workers和batch-size的理解 - 2

    关于yolov5训练时参数workers和batch-size的理解yolov5训练命令workers和batch-size参数的理解两个参数的调优总结yolov5训练命令python.\train.py--datamy.yaml--workers8--batch-size32--epochs100yolov5的训练很简单,下载好仓库,装好依赖后,只需自定义一下data目录中的yaml文件就可以了。这里我使用自定义的my.yaml文件,里面就是定义数据集位置和训练种类数和名字。workers和batch-size参数的理解一般训练主要需要调整的参数是这两个:workers指数据装载时cpu所使

随机推荐