jjzjj

【创作赢红包】< 二叉树OJ题(一) >单值二叉树&&二叉树的最大深度&&翻转二叉树&&相同的树&&对称二叉树

Sherry的成长之路 2024-05-27 原文

​📝个人主页:@Sherry的成长之路
🏠学习社区:Sherry的成长之路(个人社区)
📖专栏链接:数据结构
🎯长路漫漫浩浩,万事皆有期待

文章目录

二叉树OJ练习(一)

1. 单值二叉树

链接:单值二叉树
题述:如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树。只有给定的树是单值二叉树时,才返回 true;否则返回 false。

示例 1:
输入:[1,1,1,1,1,null,1]
输出:true

示例 2:
输入:[2,2,2,5,2]
输出:false

提示:
两棵树上的节点数目都在范围 [0, 100] 内
-104 <= Node.val <= 104

核心思想:

在数学中大家都知道等号具有传递性,如 a = b , b = c,那么 a = c 。那么这里
a == b && a == c
b == d && b == e
… …

思路:
判断两棵树是否相等,我们先思考一下如何才算相等:

1.对于 两棵空树 ,必定相等,返回真;
2.如果 一棵树空,另一棵树不为空 ,那么不相等,返回假
3.如果 树中值相同但是结构不同 ,那么也不相等,返回假;
4.如果 两棵树对应节点的值不相等,那么也不相等,返回假;

那么只要分别递归两棵的左右子树,如果一直递归到底都是真,且左右子树返回的结果都为真,那么这两棵树就相同。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>

typedef int BTDataType;
typedef struct TreeNode 
{
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
}BTNode;
//单值二叉树
bool isUnivalTree(struct TreeNode* root) {
	if (root == NULL)
	{
		return true;
	}
	//左树不为空且左树不等于根val
	if (root->left && root->left->val != root->val)
	{
		return false;		
	}
	//右树不为空且右树不等于根val
	if (root->right && root->right->val != root->val)
	{
		return false;
	}
	//递归
	return isUnivalTree(root->left) && isUnivalTree(root->right);
}
//malloc空间
BTNode* BuyNode(BTDataType x)
{
	BTNode* node = malloc(sizeof(BTNode));
	node->val = x;
	node->left = NULL;
	node->right = NULL;

	return node;
}
//创建树
BTNode* CreatBinaryTree()
{
	BTNode* node1 = BuyNode('A');
	BTNode* node2 = BuyNode('A');
	BTNode* node3 = BuyNode('A');
	BTNode* node4 = BuyNode('A');
	BTNode* node5 = BuyNode('A');
	BTNode* node6 = BuyNode('A');

	node1->left = node2;
	node1->right = node3;
	node2->left = node4;
	node2->right = node5;
	node3->right = node6;

	return node1;
}

int main()
{
	BTNode* root = CreatBinaryTree();
	printf("%d\n", isUnivalTree(root));
	return 0;
}

2. 二叉树的最大深度

链接:二叉树的最大深度

给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。

示例:

思路:与上一篇博客中求树的高度/深度同理

int maxDepth(struct TreeNode* root)
{
    if (root == NULL)
	{
		return 0;
	}
	int leftDepth = maxDepth(root->left);
	int rightDepth = maxDepth(root->right);

	return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}

3. 翻转二叉树

链接:226. 翻转二叉树

描述:给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

示例1:
输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]

示例2:
输入:root = [2,1,3]
输出:[2,3,1]

示例3:

输入:root = []
输出:[]

提示:
树中节点数目范围在 [0, 100] 内
-100 <= Node.val <= 100

思路:对于翻转二叉树,就是把一棵树所有的左右子树对调,这里我们可以使用后序遍历的思想。

那么我们基本就可以写出我们的思路:
如果节点为空,那么无需翻转,返回 NULL;
否则就先递归左子树,再递归右子树,到底后,开始交换左右子树,最后逐层返回。

struct TreeNode* invertTree(struct TreeNode* root)
{
    //如果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;
}

4. 相同的树

链接:100. 相同的树

描述:
给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

示例 1:
输入:p = [1,2,3], q = [1,2,3]
输出:true

示例 2:
输入:p = [1,2], q = [1,null,2]
输出:false

示例 3:
输入:p = [1,2,1], q = [1,1,2]
输出:false

注意:
两棵树上的节点数目都在范围 [0, 100] 内
-104 <= Node.val <= 104

核心思想:在递归时每一层函数的栈帧中存在这样的条件:p 为空,q 也为空,返回 true;p 或者 q 只有一个为空,返回 false;p 和 q 的 val 不等,返回 false;否则 p 和 q 的 val 是相等的才递归

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);
 }

5. 对称二叉树

链接:101. 对称二叉树

描述:给你一个二叉树的根节点 root , 检查它是否轴对称。

示例 1:
[1,2,2,3,4,4,3] 是镜像对称的

示例 2:
[1,2,2,null,3,null,3] 则不是镜像对称的

思路1:

一棵树是否轴对称,可以理解为它的根节点的某一边子树翻转后是否和另一边为相同的树

我们上方相同的树翻转二叉树刚刚写过,那么写这种思路就很简单了。

如果左右子树都为空,为根节点,那么返回真;
如果左右子树一边不为空,那么返回假;
如果左右子树都不为空,那么给定 left 和 right 分别记录左右子树。翻转左边,记录右边;
最后返回判断左右子树是否为相同的树。

struct TreeNode* invertTree(struct TreeNode* root)
{
    //如果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;
}

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 isSymmetric(struct TreeNode* root)
{
    //左右子树都为空
    if(root->left==NULL&&root->right==NULL)
    {
        return true;
    }

    //左右子树一边不为空
    if(root->left==NULL||root->right==NULL)
    {
        return false;
    }

    //左右子树两边都不为空
    struct TreeNode*left,*right;
    if(root->left&&root->right)
    {
        //翻转左边
        left=invertTree(root->left);
        right=root->right;
    }

    //和右边子树比较,返回bool值
    return isSameTree(left,right);

}

但是这种方法有一定缺陷,因为破坏了原本二叉树的结构,有更好的方法吗?

思路2:

一棵树对称就是 它的左右子树呈镜像状态。说白了就是节点左子树的值等于右子树的值右子树的值等于左子树的值

那么我们可以用一个 check 函数来递归检查,并将二叉树的根节点传两份过去

如果两棵树都为空,返回真;
如果两棵树一棵为空,另一棵不为空,返回假;
如果两棵树都不为空,但是值不相等,返回假;
上面都没有返回,那么分别递归第一棵树的左子树和第二棵树的右子树;第一棵树的右子树和第二棵树的左子树。
最后返回 check 函数的值,判断结果。

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


bool isSymmetric(struct TreeNode* root)
{
   
    return check(root,root);

}

总结:

今天我们分析并完成二叉树OJ题(一),通过分析明白了原理,愿这篇博客能帮助大家理解这些OJ题,因为二叉树相关OJ题是还是有一些难度和细节需要注意。下一篇博客将继续完成一些二叉树OJ题。希望我的文章和讲解能对大家的学习提供一些帮助。

当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~

有关【创作赢红包】< 二叉树OJ题(一) >单值二叉树&&二叉树的最大深度&&翻转二叉树&&相同的树&&对称二叉树的更多相关文章

  1. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  2. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  3. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  4. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  5. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  6. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  7. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  8. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  9. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  10. ruby - 无法让 RSpec 工作—— 'require' : cannot load such file - 2

    我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳

随机推荐