代码随想录算法训练营第16天 |● 104.二叉树的最大深度 559.n叉树的最大深度 ● 111.二叉树的最小深度 ● 222.完全二叉树的节点个数

本文主要是介绍代码随想录算法训练营第16天 |● 104.二叉树的最大深度 559.n叉树的最大深度 ● 111.二叉树的最小深度 ● 222.完全二叉树的节点个数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 前言
  • 104.二叉树的最大深度
    • 思路
      • 知识点
    • 方法一 递归法
    • 方法二 迭代法
  • 559. n叉树的最大深度
  • 111.二叉树的最小深度
    • 思路
    • 方法一 后向遍历递归法
    • 方法二 迭代法
  • 222.完全二叉树的节点个数
    • 思路
    • 方法一 当成普通二叉树来做
    • 方法二 利用完全二叉树的特性
  • 总结


前言

所有的题目一刷都是优先掌握递归,迭代法没看,记不住。打十个做完之后再说吧
104和111没有看先序遍历的代码

104.二叉树的最大深度

在这里插入图片描述

思路

知识点

记住深度和高度的定义:1. 从1开始 计数 2. 深度和高度与我们主观常识一致
在这里插入图片描述

总体思路:求解最大深度就是求解根节点的高度;💛

因为求深度是前序遍历,求高度是后序遍历【在子节点的高度上加1就是根节点的高度】,后序遍历要比前序遍历在本题中简洁一些,所以本题使用后序遍历的求高度;
💟具体实现细节:单层递归中求解的逻辑是,当前节点的高度为子节点高度+1;【递归法的第三步】
递归三部曲
在这里插入图片描述
先序遍历有c++代码,非常直观的从上往下的递归。也可以看

方法一 递归法

class Solution(object):def maxDepth(self, root):""":type root: TreeNode:rtype: int"""def getheight(root):if not root: return 0height_left = getheight(root.left)height_right =getheight(root.right)height = 1+max(height_left,height_right)return heightreturn getheight(root)
###精简版
class Solution(object):def maxDepth(self, root):""":type root: TreeNode:rtype: int"""if not root: return 0return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right))

方法二 迭代法

559. n叉树的最大深度

这题目我也刷了

class Solution:def maxDepth(self, root: 'Node') -> int:if not root:return 0max_depth = 1for child in root.children:max_depth = max(max_depth, self.maxDepth(child) + 1)return max_depth

111.二叉树的最小深度

在这里插入图片描述

思路

总体思路:与上面的最大深度差不多,但是不能单纯将max改成min。

  • 如果直接max改成min的话,例如下面的最右边的节点6会被算成高度为1,因为min子节点的结果为0,也就是将6当成叶子了;或者按照老师讲解的,根节点中会算左边的null为0.,这样最小深度就是1了。
    下面是老师的讲解
    在这里插入图片描述

  • 所以这条题目相较于104的改动就是加上分类讨论:(这是递归法的第三步单层逻辑)

    • 子节点中,一个是null,一个有节点,按照有节点的那个算
    • 两个都有的话选择min的那个
    • 两个都是空那就是0【可以与上面那个合并】
      在这里插入图片描述

方法一 后向遍历递归法

自己写的错误

  1. 在类里面调用递归的时候,记得加上self
  2. 下面是教程里面的代码,我写的时候is None用not来代替了,我觉着这样国家好一些
class Solution:def getDepth(self, node):if node is None:return 0leftDepth = self.getDepth(node.left)  # 左rightDepth = self.getDepth(node.right)  # 右# 当一个左子树为空,右不为空,这时并不是最低点if node.left is None and node.right is not None:return 1 + rightDepth# 当一个右子树为空,左不为空,这时并不是最低点if node.left is not None and node.right is None:return 1 + leftDepthresult = 1 + min(leftDepth, rightDepth)return resultdef minDepth(self, root):return self.getDepth(root)### 精简代码
class Solution:def minDepth(self, root):if root is None:return 0if root.left is None and root.right is not None:return 1 + self.minDepth(root.right)if root.left is not None and root.right is None:return 1 + self.minDepth(root.left)return 1 + min(self.minDepth(root.left), self.minDepth(root.right))

方法二 迭代法

222.完全二叉树的节点个数

在这里插入图片描述

思路

方法一 当成普通二叉树来做

注意:使用后序遍历的代码是最简洁的
先序遍历:参考104题目教程里面的先序遍历写法,明显会复杂一些,为啥呢,因为需要一个全局变量来++1
单层处理逻辑:后序遍历到这个节点时,已经遍历的节点个数为它的子节点个数之和+1
递归三步走:
在这里插入图片描述

每一个都需遍历一下,时间复杂度为O(n)

class Solution(object):def countNodes(self, root):""":type root: TreeNode:rtype: int"""if not root: return 0cright = self.countNodes(root.right)cleft = self.countNodes(root.left)return 1+cright+cleft

方法二 利用完全二叉树的特性

首先回顾完全二叉树定义:
在这里插入图片描述
总体思路:利用满二叉树如果知道深度为n,节点个数就是2**n-1的特性,避免遍历所有的节点;
递归第三步单层处理逻辑

  • 完全二叉树只有两种情况,情况一:就是满二叉树,情况二:最后一层叶子节点没有满。
    • 对于情况一,可以直接用 2^树深度 - 1 来计算,注意这里根节点深度为1。

    • 对于情况二,左右孩子节点数之和加1

      • 左孩子,和右孩子的计算就是递归,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照情况1来计算。

      在这里插入图片描述
      如何判断是否为完全二叉树:最左边一层和最右边一层节点数相同,这样就只需要遍历最外侧的就行
      在这里插入图片描述
      注意事项

  1. left和right侧边count的起始为1
  2. 2的阶数写为(2 << leftDepth) - 1 #注意(2<<1) 相当于2^2,所以leftDepth初始为0
class Solution(object):def countNodes(self, root):""":type root: TreeNode:rtype: int"""# if not root: return 0# cright = self.countNodes(root.right)# cleft = self.countNodes(root.left)# return 1+cright+cleftif not root: return 0#判断是否为满二叉树left = root.leftright = root.rightleft_height, right_height = 1,1# 注意这个是1while(left):left_height +=1left = left.leftwhile(right):right_height += 1right = right.rightif right_height == left_height:return 2**right_height -1cleft = self.countNodes(root.left)cright = self.countNodes(root.right)return 1+cleft+cright#还有一种技巧计算2的阶数,这时起始height要计算为0;代码如下,
class Solution:def countNodes(self, root: TreeNode) -> int:if not root:return 0left = root.leftright = root.rightleftDepth = 0 #这里初始为0是有目的的,为了下面求指数方便rightDepth = 0while left: #求左子树深度left = left.leftleftDepth += 1while right: #求右子树深度right = right.rightrightDepth += 1if leftDepth == rightDepth:return (2 << leftDepth) - 1 #注意(2<<1) 相当于2^2,所以leftDepth初始为0return self.countNodes(root.left) + self.countNodes(root.right) + 1

更加简洁的写法:完全二叉树写法2【教程里面的】
两侧同时顺着边数,直到有一条边为none,然后依据是否同时到底来判断是否为满二叉树;

class Solution: # 利用完全二叉树特性def countNodes(self, root: TreeNode) -> int:if not root: return 0count = 1left = root.left; right = root.rightwhile left and right:count+=1left = left.left; right = right.rightif not left and not right: # 如果同时到底说明是满二叉树,反之则不是return 2**count-1return 1+self.countNodes(root.left)+self.countNodes(root.right) 

总结

比较有意思,今天都不想听申论课了。还是算法好玩。。。。可惜找不到工作

这篇关于代码随想录算法训练营第16天 |● 104.二叉树的最大深度 559.n叉树的最大深度 ● 111.二叉树的最小深度 ● 222.完全二叉树的节点个数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1000080

相关文章

深度解析Nginx日志分析与499状态码问题解决

《深度解析Nginx日志分析与499状态码问题解决》在Web服务器运维和性能优化过程中,Nginx日志是排查问题的重要依据,本文将围绕Nginx日志分析、499状态码的成因、排查方法及解决方案展开讨论... 目录前言1. Nginx日志基础1.1 Nginx日志存放位置1.2 Nginx日志格式2. 499

Python实现MQTT通信的示例代码

《Python实现MQTT通信的示例代码》本文主要介绍了Python实现MQTT通信的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 安装paho-mqtt库‌2. 搭建MQTT代理服务器(Broker)‌‌3. pytho

MySQL进行数据库审计的详细步骤和示例代码

《MySQL进行数据库审计的详细步骤和示例代码》数据库审计通过触发器、内置功能及第三方工具记录和监控数据库活动,确保安全、完整与合规,Java代码实现自动化日志记录,整合分析系统提升监控效率,本文给大... 目录一、数据库审计的基本概念二、使用触发器进行数据库审计1. 创建审计表2. 创建触发器三、Java

深度解析Java DTO(最新推荐)

《深度解析JavaDTO(最新推荐)》DTO(DataTransferObject)是一种用于在不同层(如Controller层、Service层)之间传输数据的对象设计模式,其核心目的是封装数据,... 目录一、什么是DTO?DTO的核心特点:二、为什么需要DTO?(对比Entity)三、实际应用场景解析

深度解析Java项目中包和包之间的联系

《深度解析Java项目中包和包之间的联系》文章浏览阅读850次,点赞13次,收藏8次。本文详细介绍了Java分层架构中的几个关键包:DTO、Controller、Service和Mapper。_jav... 目录前言一、各大包1.DTO1.1、DTO的核心用途1.2. DTO与实体类(Entity)的区别1

Java中的雪花算法Snowflake解析与实践技巧

《Java中的雪花算法Snowflake解析与实践技巧》本文解析了雪花算法的原理、Java实现及生产实践,涵盖ID结构、位运算技巧、时钟回拨处理、WorkerId分配等关键点,并探讨了百度UidGen... 目录一、雪花算法核心原理1.1 算法起源1.2 ID结构详解1.3 核心特性二、Java实现解析2.

Java中调用数据库存储过程的示例代码

《Java中调用数据库存储过程的示例代码》本文介绍Java通过JDBC调用数据库存储过程的方法,涵盖参数类型、执行步骤及数据库差异,需注意异常处理与资源管理,以优化性能并实现复杂业务逻辑,感兴趣的朋友... 目录一、存储过程概述二、Java调用存储过程的基本javascript步骤三、Java调用存储过程示

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

深度解析Python装饰器常见用法与进阶技巧

《深度解析Python装饰器常见用法与进阶技巧》Python装饰器(Decorator)是提升代码可读性与复用性的强大工具,本文将深入解析Python装饰器的原理,常见用法,进阶技巧与最佳实践,希望可... 目录装饰器的基本原理函数装饰器的常见用法带参数的装饰器类装饰器与方法装饰器装饰器的嵌套与组合进阶技巧

深度解析Spring Boot拦截器Interceptor与过滤器Filter的区别与实战指南

《深度解析SpringBoot拦截器Interceptor与过滤器Filter的区别与实战指南》本文深度解析SpringBoot中拦截器与过滤器的区别,涵盖执行顺序、依赖关系、异常处理等核心差异,并... 目录Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现