Python蓝桥杯训练:基本数据结构 [二叉树] 中

news2024/9/27 15:20:35

Python蓝桥杯训练:基本数据结构 [二叉树] 中

文章目录

  • Python蓝桥杯训练:基本数据结构 [二叉树] 中
    • 一、[翻转二叉树](https://leetcode.cn/problems/invert-binary-tree/)
    • 二、[对称二叉树](https://leetcode.cn/problems/symmetric-tree/)
    • 三、[二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/)
    • 四、[二叉树的最小深度](https://leetcode.cn/problems/minimum-depth-of-binary-tree/)
    • 五、[完全二叉树的节点个数](https://leetcode.cn/problems/count-complete-tree-nodes/)
    • 六、[平衡二叉树](https://leetcode.cn/problems/balanced-binary-tree/)

一、翻转二叉树

给你一棵二叉树的根节点 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

这道题目要求我们翻转一棵二叉树,可以使用递归的思路来解决问题。对于一个二叉树而言,可以将它的左右子树看作两个独立的小问题,因此可以先将左右子树分别翻转,然后再将整个树进行翻转。

具体实现时,可以编写一个递归函数,对于每一个节点而言,先分别翻转左右子树,然后将左右子树交换即可。如果节点为空,直接返回即可。

class Solution:
    def invertTree(self, root: TreeNode) -> TreeNode:
        if not root:
            return None

        # 递归翻转左右子树
        left = self.invertTree(root.left)
        right = self.invertTree(root.right)

        # 交换左右子树
        root.left = right
        root.right = left

        return root

上面算法我们使用的遍历顺序是后序遍历,使用前序遍历也可以解决,该算法的时间复杂度为 O ( n ) O(n) O(n),其中 n n n 是二叉树的节点个数,因为每个节点都会被访问一次。空间复杂度为 O ( n ) O(n) O(n),因为递归函数会使用系统栈,最坏情况下系统栈的深度等于二叉树的高度,即为 O ( n ) O(n) O(n)

二、对称二叉树

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

示例 1:

在这里插入图片描述

输入:root = [1,2,2,3,4,4,3]
输出:true

示例 2:

在这里插入图片描述

输入:root = [1,2,2,null,3,null,3]
输出:false

提示:

  • 树中节点数目在范围 [1, 1000]
  • -100 <= Node.val <= 100

**进阶:**你可以运用递归和迭代两种方法解决这个问题吗?

首先,可以通过递归的方法来判断一棵二叉树是否是镜像对称的。对于一棵二叉树而言,如果它是镜像对称的,那么它的左右子树也是镜像对称的。因此,可以编写一个递归函数来判断左右子树是否镜像对称,然后判断根节点的左右子树是否镜像对称即可。

具体实现时,可以编写一个递归函数 isMirror,该函数接受两个参数 leftright,分别表示两棵子树。如果两棵子树均为空,返回 True;如果其中一棵子树为空,返回 False;如果两棵子树的根节点的值不相等,返回 False;否则,递归判断两棵子树的左右子树是否镜像对称。

class Solution(object):
    def isSymmetric(self, root):
        # 如果二叉树为空,则直接返回 True
        if not root:
            return True
        # 如果二叉树不为空,则递归判断其左右子树是否镜像对称
        return self.isMirror(root.left, root.right)
    
    def isMirror(self, left, right):
        # 如果两棵二叉树均为空,则返回 True
        if not left and not right:
            return True
        # 如果其中一棵二叉树为空,则返回 False
        if not left or not right:
            return False
        # 如果两棵二叉树的根节点的值不相等,则返回 False
        if left.val != right.val:
            return False
        # 递归判断两棵二叉树的左右子树是否镜像对称
        return self.isMirror(left.left, right.right) and self.isMirror(left.right, right.left)

三、二叉树的最大深度

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

示例:

给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回它的最大深度 3 。

题目要求找出二叉树的最大深度,因此可以通过深度优先搜索的方式,而且推荐使用后序遍历来遍历二叉树,记录每个节点的深度,然后返回最大深度即可。

具体实现时,可以编写一个递归函数 maxDepth,该函数接受一个参数 node,表示当前节点。如果当前节点为空,则返回 0;否则,分别递归遍历当前节点的左右子树,返回左右子树深度的较大值加上 1,即为当前节点的深度。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def maxDepth(self, root):
        # 如果二叉树为空,则返回 0
        if not root:
            return 0
        # 分别递归遍历当前节点的左右子树
        left_depth = self.maxDepth(root.left)
        right_depth = self.maxDepth(root.right)
        # 返回左右子树深度的较大值加上 1,即为当前节点的深度
        return max(left_depth, right_depth) + 1

四、二叉树的最小深度

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

**说明:**叶子节点是指没有子节点的节点。

示例 1:

在这里插入图片描述

输入:root = [3,9,20,null,null,15,7]
输出:2

示例 2:

输入:root = [2,null,3,null,4,null,5,null,6]
输出:5

提示:

  • 树中节点数的范围在 [0, 105]
  • -1000 <= Node.val <= 1000

题目要求找出二叉树的最小深度,因此我妈可以通过深度优先搜索的方式来遍历二叉树,记录每个节点的深度,然后返回最小深度即可。

具体实现时,可以编写一个递归函数 minDepth,该函数接受一个参数 node,表示当前节点。如果当前节点为空,则返回 0;否则,分别递归遍历当前节点的左右子树,如果当前节点有左右子树,则返回左右子树深度的较小值加上 1,否则返回左右子树深度的较大值加上 1,即为当前节点的深度。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def minDepth(self, root):
        # 如果二叉树为空,则返回 0
        if not root:
            return 0
        # 分别递归遍历当前节点的左右子树
        left_depth = self.minDepth(root.left)
        right_depth = self.minDepth(root.right)
        if not root.left or not root.right:
            # 如果当前节点只有一个子节点,则返回另一个子树的深度加上 1
            return left_depth + right_depth + 1
        else:
            # 如果当前节点有左右子树,则返回左右子树深度的较小值加上 1
            return min(left_depth, right_depth) + 1

这里需要注意的是,在计算当前节点只有一个子节点的情况时,我们需要将其另一个子树的深度加上 1,因为当前节点不是叶子节点,而是只有一个子节点的非叶子节点。

五、完全二叉树的节点个数

给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。

完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。

示例 1:

在这里插入图片描述

输入:root = [1,2,3,4,5,6]
输出:6

示例 2:

输入:root = []
输出:0

示例 3:

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

提示:

  • 树中节点的数目范围是[0, 5 * 104]
  • 0 <= Node.val <= 5 * 104
  • 题目数据保证输入的树是 完全二叉树

**进阶:**遍历树来统计节点是一种时间复杂度为 O(n) 的简单解决方案。你可以设计一个更快的算法吗?

在这里我们可以直接当作普通二叉树来处理,也就是之前练习的层序遍历,直接使用那个模板,记录遍历的节点数量就可以了。

在这里我们主要来着重利用完全二叉树的性质来解决问题,由于完全二叉树的特殊性质,我们可以先分别求出左子树和右子树的高度,然后根据它们的高度分情况讨论。

  • 如果左右子树的高度相同,说明左子树是一棵满二叉树,右子树是一棵完全二叉树,那么左子树的节点个数可以直接计算,右子树的节点个数可以递归地求解。
  • 如果左右子树的高度不同,说明右子树是一棵满二叉树,左子树是一棵完全二叉树,那么右子树的节点个数可以直接计算,左子树的节点个数可以递归地求解。

最终,根据上述讨论的结果,我们可以递归地求解出完全二叉树的节点个数。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def countNodes(self, root):
        if not root:
            return 0
        
        # 分别求出左子树和右子树的高度
        left_height = self.get_height(root.left)
        right_height = self.get_height(root.right)
        
        # 如果左右子树的高度相同,说明左子树是一棵满二叉树,右子树是一棵完全二叉树
        if left_height == right_height:
            # 左子树的节点个数可以直接计算
            return (1 << left_height) + self.countNodes(root.right)
        # 如果左右子树的高度不同,说明右子树是一棵满二叉树,左子树是一棵完全二叉树
        else:
            # 右子树的节点个数可以直接计算
            return (1 << right_height) + self.countNodes(root.left)
        
    def get_height(self, node):
        height = 0
        while node:
            height += 1
            node = node.left
        return height

我们也可以换一个实现思路,首先判断二叉树是否为空,若为空则节点个数为0,直接返回;否则,记录左子树和右子树的根节点,同时记录左子树和右子树的深度,初始值都为0。

接着,通过循环,不断地遍历左子树和右子树,直到无法遍历,统计出左子树和右子树的深度。

如果左子树的深度等于右子树的深度,说明左子树是满二叉树,右子树是完全二叉树,此时可以利用满二叉树的节点数公式计算出总节点数,即 2 l e f t D e p t h + 1 − 1 2^{leftDepth+1}-1 2leftDepth+11,其中 l e f t D e p t h leftDepth leftDepth 表示左子树的深度。

如果左子树的深度不等于右子树的深度,说明左子树是完全二叉树,右子树是满二叉树,此时可以递归计算左子树和右子树的节点个数,并将它们加起来再加上根节点,即可得到总节点数。

最终返回计算出的节点数即可。

class Solution:
    def countNodes(self, root) -> int:
        if not root:
            return 0
        left = root.left
        right = root.right
        leftDepth = 0 #这里初始为0是有目的的,为了下面求指数方便
        rightDepth = 0
        while left: #求左子树深度
            left = left.left
            leftDepth += 1
        while right: #求右子树深度
            right = right.right
            rightDepth += 1
        if leftDepth == rightDepth:
            return (2 << leftDepth) - 1 #注意(2<<1) 相当于2^2,所以leftDepth初始为0
        return self.countNodes(root.left) + self.countNodes(root.right) + 1

六、平衡二叉树

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

示例 1:

在这里插入图片描述

输入:root = [3,9,20,null,null,15,7]
输出:true

示例 2:

在这里插入图片描述

输入:root = [1,2,2,3,3,null,null,4,4]
输出:false

示例 3:

输入:root = []
输出:true

提示:

  • 树中的节点数在范围 [0, 5000]
  • -104 <= Node.val <= 104

首先我们需要思考的是对于一棵二叉树,如果它是一棵空树,则它是平衡二叉树,因为它没有任何节点,高度为0。

接着,我们可以通过递归的方式判断以每个节点为根的子树是否是平衡二叉树。

对于每个节点,我们需要计算它的左子树和右子树的高度,并判断它们的高度差是否大于1,如果大于1,则说明该节点的子树不是平衡二叉树;否则,递归判断它的左子树和右子树是否是平衡二叉树,如果左子树和右子树都是平衡二叉树,则该节点的子树也是平衡二叉树。

最终,如果整个二叉树是平衡二叉树,则返回True,否则返回False。

class Solution:
    def isBalanced(self, root) -> bool:
        # 调用方法 getHeight 来获取二叉树的高度
        if self.getHeight(root) != -1:
            return True
        else:
            return False
        
    def getHeight(self, root):
        # 如果当前节点是空节点,则返回0
        if not root:
            return 0
        # 分别计算当前节点的左右子树的高度
        # 如果左右子树的高度差大于1,则说明该节点不是平衡二叉树,返回-1
        # 否则,返回该节点的高度
        if (leftHeight := self.getHeight(root.left)) == -1:
            return -1
        if (rightHeight := self.getHeight(root.right)) == -1:
            return -1
        if abs(leftHeight - rightHeight) > 1:
            return -1
        else:
            return 1 + max(leftHeight, rightHeight)

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

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

相关文章

Vue3这样子写页面更快更高效

在开发管理后台过程中,一定会遇到不少了增删改查页面,而这些页面的逻辑大多都是相同的,如获取列表数据,分页,筛选功能这些基本功能。而不同的是呈现出来的数据项。还有一些操作按钮。 对于刚开始只有 1,2 个页面的时候大多数开发者可能会直接将之前的页面代码再拷贝多…

工作记录:调研monorepo和微前端

2023年1月。因工作项目需要&#xff0c;调研 monorepo 、微前端等技术。 任务 一直在做的 BI 项目&#xff0c;随着需求迭代&#xff0c;模块越来越多&#xff0c;项目越来越复杂、臃肿。 最近&#xff0c;前一阶段的开发工作基本结束。新模块还在设计阶段。借此契机&#xf…

进阶C语言——数据的存储【详解】

文章目录1. 数据类型介绍1.1 类型的基本归类2. 整形在内存中的存储2.1 原码、反码、补码2.2 大小端介绍2.3 练习3. 浮点型在内存中的存储3.1 一个例子3.2 浮点数存储的规则1. 数据类型介绍 前面我们已经学习了基本的内置类型&#xff1a; char //字符数据类型 short //短整型 …

学习ForkJoin

学习ForkJoin一、普通解决多线程方式1、案例一2、效果图二、ForkJoin一、普通解决多线程方式 1、案例一 大数据量的List问题处理&#xff0c;多线程分批处理&#xff0c;需要解决的问题&#xff1a; 下标越界。线程安全。数据丢失。 private static ThreadPoolExecutor thre…

链表OJ之 快慢指针法总结

欢迎来到 Claffic 的博客 &#x1f49e;&#x1f49e;&#x1f49e; 前言&#xff1a; 快慢指针指的是每次指针移动的步长&#xff0c;是解决链表相关的题目的一大利器&#xff0c;下面我将以例题的形式讲解快慢指针法。 目录 一. 链表的中间结点 思路&#xff1a; 代码实…

GMP调度模型总结

优秀文章 什么是GMP调度模型 Golang的一大特色就是Goroutine。Goroutine是Golang支持高并发的重要保障。Golang可以创建成千上万个Goroutine来处理任务&#xff0c;将这些Goroutine分配、负载、调度到处理器上采用的是G-M-P模型。 什么是Goroutine Goroutine Golang Coro…

云舟案例︱视频孪生技术赋能城市安全综合管理场景,提升城市数智化水平

随着城市化发展进程的加快&#xff0c;人口不断膨胀&#xff0c;社会安全隐患等问题日益突出&#xff0c;成为困扰城市建设与管理的重要难题。针对各类社会治安突出问题&#xff0c;城市管理部门积极推进城市信息化建设&#xff0c;视频监控等各类信息化采集手段为城市数字化管…

嵌入式学习笔记——使用寄存器编程实现按键输入功能

文章目录前言模块介绍原理图编程思路前言 昨天&#xff0c;通过配置通用输出模式&#xff0c;实现了LED灯的点亮、熄灭以及流水等操作&#xff0c;解决了通用输出的问题&#xff0c;今天我们再借用最常见的输入模块&#xff0c;按键来实现一个按键控制LED的功能&#xff0c;重…

SpringBoot【知识加油站】---- REST开发

SpringBoot【知识加油站】---- REST开发1. REST 简介2. REST 风格3. RESTful 入门案例1. REST 简介 REST&#xff1a;Representaional State Transfer&#xff0c;表现形式状态转换 传统风格资源描述形式 http://localhost/user/getById?id1 http://localhost/user/saveUser…

91. 解码方法 ——【Leetcode每日刷题】

91. 解码方法 一条包含字母 A-Z 的消息通过以下映射进行了 编码 &#xff1a; ‘A’ -> “1” ‘B’ -> “2” … ‘Z’ -> “26” 要 解码 已编码的消息&#xff0c;所有数字必须基于上述映射的方法&#xff0c;反向映射回字母&#xff08;可能有多种方法&#xff0…

Kubernetes13:Ingress

Kubernetes13&#xff1a;Ingress 1、把端口号对外暴露&#xff0c;通过ip端口号进行访问 使用Service里面的NodePort实现&#xff08;Cluster、LoadBanlancer、NodePort&#xff09; 2、NodePort缺陷 在每个节点上启动一个端口&#xff0c;在访问时候通过任何节点&#xf…

MySQL(五)锁

锁全局锁表级锁表锁元数据锁意向锁行级锁行锁间隙锁&临键锁总结计算机用锁来协调多个进程或线程并发访问某一资源。在数据库中&#xff0c;除传统的计算资源&#xff08;CPU、RAM、I/O&#xff09;的争用以外&#xff0c;数据也是一种供许多用户共享的资源。如何保证数据并…

业务流程图TFD和数据流程图DFD例题

业务流程图&#xff08;TFD&#xff09;管理业务流程图&#xff08;Transaction Flow Diagram&#xff0c;简称TFD&#xff09;用来描述系统各部门、人员之间存在的业务关系、作业顺序以及管理信息流向的图表。绘制该图使用以下四种符号&#xff1a;例题例题1&#xff1a;物资订…

【Unity逆向】玩游戏遇到的“飞天锁血”是怎么实现的?

文章目录前言什么是外挂&#xff1f;锁血瞬移都是怎么做的&#xff1f;Unity引擎的致命缺陷是什么&#xff1f;WEB入侵如何做到&#xff1f;Unity外挂攻防概述典型游戏现实应用Unity开发流程Unity工作界面打包发布方式MonoMono跨平台原理JIT方式优点&#xff1a;因此后期Unity发…

【数据分析师求职面试指南】实战技能部分

文章目录必备技能数据人员如何创造价值完整的指标体系构建数据监控集报表设计设计一份优质的数据分析报告基于互联网大数据的应用A B 测试用户画像完整的数据挖掘项目流程1. ​分析问题&#xff0c;明确目标2.模型可行性分析3.选取模型4.选择变量5.特征工程6.建立模型&效果…

大数据项目实战之数据仓库:用户行为采集平台——第4章 用户行为数据采集模块

第4章 用户行为数据采集模块 4.1 数据通道 4.2 环境准备 4.2.1 集群所有进程查看脚本 1&#xff09;在/home/atguigu/bin目录下创建脚本xcall [atguiguhadoop102 bin]$ vim xcall2&#xff09;在脚本中编写如下内容 #! /bin/bashfor i in hadoop102 hadoop103 hadoop104 d…

判断推理之类比推理与定义判断

考点一包含关系&#xff08;一&#xff09;种属关系快速判定方法&#xff1a;XX是一种XX。(可以用“是”来造句子)如&#xff1a;苹果&#xff1a;水果&#xff1b;老虎&#xff1a;哺乳动物&#xff08;二&#xff09;组成关系快速判定方法&#xff1a;A是B的一部分。(不可以用…

支持向量回归删除异常值Python

1、支持向量回归&#xff08;SVR&#xff09;原理 支持向量回归&#xff08;Support Vector Regression&#xff0c;SVR&#xff09;不仅可以用于预测&#xff0c;还可以用于异常值检测。其基本思路是训练一个回归模型&#xff0c;通过对每个数据点进行预测&#xff0c;并计算…

基于Transformer的目标检测算法学习记录

前言 本文主要通过阅读相关论文了解当前Transformer在目标检测领域的应用与发展。 谷歌在 ICLR2020 上提出的 ViT&#xff08;Vision Transformer&#xff09;是将 Transformer 应用在视觉领域的先驱。从此&#xff0c;打开了Transformer进入CV领域的桥梁&#xff0c;NLP与CV几…

软件测试11

一 Linux命令的基本格式 格式组成&#xff1a;命令主体 -命令选项 命令参数 常见命令形式&#xff1a; &#xff08;1&#xff09;命令主体 &#xff08;2&#xff09;命令主体 -命令选项 &#xff08;3&#xff09;命令主体 参数 &#xff08;4&#xff09;命令主体 -命令选项…