【Leetcode】代码随想录Day16|二叉树3.0

news2024/9/20 8:00:40

文章目录

    • 104 二叉树的最大深度
    • 559 n叉树的最大深度
    • 111 二叉树的最小深度
    • 222 完全二叉树的节点个数

104 二叉树的最大深度

  • 递归法:无论是哪一种顺序,标记最大深度
class Solution(object):
    def depthHelper(self, root, depth):
        if root:
            depth += 1
            left_depth = self.depthHelper(root.left, depth)
            right_depth = self.depthHelper(root.right, depth)
            return max(left_depth, right_depth)
        return depth

    def maxDepth(self, root):
        depth = 0
        if root:
            depth = self.depthHelper(root, depth)
        return depth
        

优解参考简化:

class Solution(object):
    def maxDepth(self, root):
        if not root:
            return 0
        ldepth = self.maxDepth(root.left)
        rdepth = self.maxDepth(root.right)
        return max(ldepth,rdepth) + 1
  • 迭代法:层序遍历
class Solution:
    def maxDepth(self, root: TreeNode) -> int:
        if not root:
            return 0
        
        depth = 0
        queue = collections.deque([root])
        
        while queue:
            depth += 1
            for _ in range(len(queue)):
                node = queue.popleft()
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
        
        return depth

559 n叉树的最大深度

  • 递归法:需要遍历每个节点的children
"""
# Definition for a Node.
class Node(object):
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children
"""

class Solution(object):
    def maxDepth(self, root):
        if not root:
            return 0
        childDepth = 0
        if root.children:
            childDepth = max([self.maxDepth(child) for child in root.children])
        return 1 + childDepth

111 二叉树的最小深度

初始思路
与最大深度一样

class Solution(object):
    def minDepth(self, root):
        if not root:
            return 0
        ldepth = self.minDepth(root.left)
        rdepth = self.minDepth(root.right)
        return min(ldepth,rdepth) + 1

问题:
最大深度只要有一个分支有更深的深度,取这个深度就可以了,所有累积到此的分支都是存在的,他们的深度代表了树的深度。但是上述方法中的最小分支却可能是树并不存在的分支,也就不能代表树的深度。如下面这个例子,这个树的深度是3,但是如果用与之前类似的方法,那么在1这个root左子树不存在的时候,就会认为找到了最短的路径深度1。事实上1并不是叶子结点,并不符合对与树深度的定义。所以在找最小路径的时候,要考虑找到的深度究竟能不能算做是整个树的深度。

      1
       \
        2
       /
      3 

转换思路:
需要判断分支深度为0的情况,如果有且只有一个分支深度为0,那么这个后面的深度是需要算上的,并不能因为其中一个分支深度为0,就在这里截止,当作最小深度的情况。

class Solution(object):
    def minDepth(self, root):
        if not root:
            return 0
        
        left = self.minDepth(root.left)
        right = self.minDepth(root.right)
        minDepth = 0
        if left == 0 and right != 0:
            minDepth = right
        elif left != 0 and right == 0:
            minDepth = left
        else:
            return 1 + min(left, right)
        return 1 + minDepth

222 完全二叉树的节点个数

1. 初始思路
递归或迭代遍历所有节点

  • 递归
class Solution(object):
    def countNodes(self, root):
        if not root:
            return 0
        
        left = self.countNodes(root.left)
        right = self.countNodes(root.right)
        return left + right + 1

Complexity
time: O(n)
space: O(log n),算上了递归系统栈占用的空间

  • 迭代:

Complexity
time: O(n)
space: O(n)

2. 利用完全二叉树的特性

首先我们最想用的肯定是满二叉树,因为直接通过层数就可以算出来节点数量2^h - 1。 但是完全二叉树可能有两种情况:

  • 满二叉树
  • 距离满二叉树只有最后一层按顺序没有填满

为了能够利用简介的满二叉树算法,我们可以通过递归去将输入的树拆解成子满二叉树。对于一个完全二叉树来讲,会有两种拆解方式:
来自代码随想录

来自代码随想录

那么如何判断是否是满二叉树呢?
既然非满二叉树的完全二叉树只有可能是最后一层按照从左往右的顺序右边没有填满,那么只要查看一个树的最后一层的最左边的深度和最后一层的最右边的深度是否一样,就可以判断它是不是满的。

那么总结一下方法:就是往下递归找到最大块的满二叉树组成部分,来计算总共的节点数。

class Solution(object):
    def getFullHeight(self, root):
        # return -1 if it is not full
        # else, return the height of the full binary tree
        if not root:
            return 0
        left = 1
        right = 1
        lefttmp = root
        righttmp = root
        while lefttmp.left:
            lefttmp = lefttmp.left
            left += 1
        while righttmp.right:
            righttmp = righttmp.right
            right += 1
        if left == right:
            return left
        return -1 
        
        
    def countNodes(self, root):
        if not root:
            return 0
        h = self.getFullHeight(root)
        if h == -1:
            return 1 + self.countNodes(root.left) + self.countNodes(root.right)
        return 2**h - 1

优解参考简化

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

优化二:将getFullHeight的操作明确只对剩下的一半进行,让另一半以O(1)的复杂度完成,不需要再判断一次满二叉树了。

class Solution:
       def countNodes(self, root):
           if not root:
               return 0
           leftDepth = self.getDepth(root.left)
           rightDepth = self.getDepth(root.right)
           if leftDepth == rightDepth:
               return pow(2, leftDepth) + self.countNodes(root.right)
           else:
               return pow(2, rightDepth) + self.countNodes(root.left)
   
       def getDepth(self, root):
           if not root:
               return 0
           return 1 + self.getDepth(root.left)

Complexity
time: O(log n × log n)
space: O(log n)

时间复杂度的解释
H为整个树的高度,n为总节点数。

  1. 判断是否为满二叉树及其深度的时间复杂度为O(H) = O(log n) 【getFullHeight】

  2. 从上面两种由满二叉树构成完全二叉树的方式中可以看出,root.right只有两种可能的高度,H-1或H-2

    • H-1: 少的这个高度就是root那一层,则root.left和root.right相同高度。也就是说,root.left一定是满二叉树,只需要O(1)就可以算出节点数,root.right需要进一步递归判断节点数。
    • H-2:不仅少了root一层的高度,root.left比root.right高一层。也就是说最后一层不满的叶子结点全部都在root.left的范围里面,需要进一步递归判断节点数,而root.right是一个满二叉树,只需要O(1)就可以算出节点数。
  3. 从最后优化版中可以看到,在H层中,递归到每一层的时候,都有一半是满二叉树,可以用O(1) 的方式直接计算出数量,只需要进行一次【getFullHeight】,即对于O(log n)层,每一层进行一次O(log n)的操作,复杂度为 O(log n × log n)

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

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

相关文章

GPT 交互式提示工程

简介:交互式提示工程 人工智能领域,尤其是 GPT(生成式预训练变压器)等工具,凸显了即时工程的关键作用。 这篇扩展文章深入探讨了如何设计有效的提示,以从 GPT 等 AI 模型中获得出色的响应。 了解即时工程即…

尚硅谷html5+css3(4)浮动

1.浮动的概念 <head><style>.box1 {width: 200px;height: 200px;background-color: orange;/*通过浮动可以使一个元素向其父元素的左侧或右侧移动使用float属性设置子资源的浮动可选值&#xff1a;none默认值&#xff0c;元素不浮动left向左浮动right向右浮动注意…

分布式监控平台---Zabbix

一、Zabbix概述 作为一个运维&#xff0c;需要会使用监控系统查看服务器状态以及网站流量指标&#xff0c;利用监控系统的数据去了解上线发布的结果&#xff0c;和网站的健康状态。 利用一个优秀的监控软件&#xff0c;我们可以&#xff1a; 通过一个友好的界面进行浏览整个…

SETR——Rethinking系列工作,展示使用纯transformer在语义分割任务上是可行的,但需要很强的训练技巧

题目:Rethinking Semantic Segmentation from a Sequence-to-Sequence Perspective with Transformers 作者: 开源:https://fudan-zvg.github.io/SETR 1.研究背景 1.1 为什么要研究这个问题? 自[ 36 ]的开创性工作以来,现有的语义分割模型主要是**基于全卷积网络( FCN )的…

【机器学习300问】69、为什么深层神经网络比浅层要好用?

要回答这个问题&#xff0c;首先得知道神经网络都在计算些什么东西&#xff1f;之前我在迁移学习的文章中稍有提到&#xff0c;跳转链接在下面&#xff1a; 为什么其他任务预训练的模型参数&#xff0c;可以在我这个任务上起作用&#xff1f;http://t.csdnimg.cn/FVAV8 …

go work模块与go mod包管理是的注意事项

如下图所示目录结构 cmd中是服务的包&#xff0c;显然auth,dbtables,pkg都是为cmd服务的。 首先需要需要将auth,dbtables,pkg定义到go.work中&#xff0c;如下&#xff1a; 在这样在各个单独的go mod管理的模块就可以互相调用了。一般情况下这些都是IDE自动进行的&#xff0c;…

js纯前端实现语音播报,朗读功能(2024-04-15)

实现语音播报要有两个原生API 分别是【window.speechSynthesis】【SpeechSynthesisUtterance】 项目代码 // 执行函数 initVoice({text: 项目介绍,vol: 1,rate: 1 })// 函数 export function initVoice(config) {window.speechSynthesis.cancel();//播报前建议调用取消的函数…

CSS使用自己的字体

在项目的根目录下的static文件夹中放置字体文件。在项目中使用这个字体&#xff0c;需要2个步骤。 一. 你需要在全局样式文件中引入它。 假设你的全局样式文件是App.vue或者App.vue中引入的App.scss文件&#xff0c;你可以像这样引入字体文件&#xff1a; font-face {font-fa…

自然语言控制机械臂:ChatGPT与机器人技术的融合创新(下)

引言 在我们的上一篇文章中&#xff0c;我们探索了如何将ChatGPT集成到myCobot 280机械臂中&#xff0c;实现了一个通过自然语言控制机械臂的系统。我们详细介绍了项目的动机、使用的关键技术如ChatGPT和Google的Speech-to-text服务&#xff0c;以及我们是如何通过pymycobot模块…

C++面向对象程序设计 - 类和对象进一步讨论

在C中&#xff0c;关于面向对象程序设计已经讲了很大篇幅&#xff0c;也例举很多案例&#xff0c;此篇将通过一些习题来进一步了解对象、静态成员、指针、引用、友元、类模板等等相关知识。 一、习题一&#xff08;构造函数默认参数&#xff09; 示例代码&#xff1a; #includ…

主流App UI设计,7个在线平台供您选择!

在数字时代&#xff0c;用户界面&#xff08;UI&#xff09;设计变得非常重要&#xff0c;因为良好的UI设计可以改善用户体验&#xff0c;增强产品吸引力。随着技术的发展&#xff0c;越来越多的应用程序 ui在线设计网站的出现为设计师和团队提供了一种全新的创作方式。本文将盘…

关于Wordpress的操作问题1:如何点击菜单跳转新窗口

1.如果打开&#xff0c;外观-菜单-菜单结构内&#xff0c;没有打开新窗口属性&#xff0c;如图&#xff1a; 2.在页面的最上部&#xff0c;点开【显示选项】&#xff0c;没有这一步&#xff0c;不会出现新跳转窗口属性 3.回到菜单结构部分&#xff0c;就出现了

Mysql嵌套查询太简单了

1、子查询的分类 不相关查询&#xff1a; 子查询能独立执行 相关查询&#xff1a; 子查询不能独立运行 相关查询的执行顺序&#xff1a; 首先取外层查询中表的第一个元组,根据它与内层查询相关的属性值处理内层查询, 若WHERE子句返回值为真&#xff0c;则取此元组放入结果…

CSS基础:margin属性4种值类型,4个写法规则详解

你好&#xff0c;我是云桃桃。 一个希望帮助更多朋友快速入门 WEB 前端的程序媛。大专生&#xff0c;一枚程序媛&#xff0c;感谢关注。回复 “前端基础题”&#xff0c;可免费获得前端基础 100 题汇总&#xff0c;回复 “前端工具”&#xff0c;可获取 Web 开发工具合集 268篇…

PaddleOCR训练自己模型(1)----数据准备

一、下载地址&#xff1a; PaddleOCR开源代码&#xff08;下载的是2.6RC版本的&#xff0c;可以根据自己需求下载&#xff09; 具体环境安装就不详细介绍了&#xff0c; 挺简单的&#xff0c;也挺多教程的。 二、数据集准备及制作 &#xff08;1&#xff09;下载完代码及配置…

Navicat for MySQL 使用基础与 SQL 语言的DDL

一、目的&#xff1a; Navicat for MySQL 是一套专为 MySQL 设计的高性能数据库管理及开发 工具。它可以用于任何版本 3.21 或以上的 MySQL 数据库服务器&#xff0c;并支持大 部份 MySQL 最新版本的功能&#xff0c;包括触发器、存储过程、函数、事件、视图、 管理用户等。…

软件工程及开发模型

根据希赛相关视频课程汇总整理而成&#xff0c;个人笔记&#xff0c;仅供参考。 软件工程的基本要素包括方法、工具和&#xff08;过程&#xff09; 方法&#xff1a;完成软件开发的各项任务的技术方法&#xff1b; 工具&#xff1a;运用方法而提供的软件工程支撑环境&#xff…

数据结构 -- 二分查找

本文主要梳理了二分查找算法的几种实现思路&#xff0c;基本概念参考 顺序、二分、哈希查找的区别及联系_生成一个大小为10万的有序数组,随机查找一个元素,分别采用顺序查找和二分查找方式-CSDN博客 1、基本概念 &#xff08;1&#xff09;前提条件&#xff1a;待查找数据必须…

Leetcode二叉树刷题

给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true public boolean isSymmetric(TreeNode root) {if(rootnull)return true;return compare(root.left,root.right);}public boole…

【Unity】游戏场景添加后处理特效PostProcessing

添加后处理特效PostProcessing 添加雾效果后处理何为后处理&#xff1f;添加后处理特效 添加雾效果 依次点击Window -> Rendering -> Lighting添加Lighting面板。 点击Lighting里面的Environment&#xff0c;找到Other Setting 将Fog选项勾选 更改下方的颜色 调整雾的浓…