LeetCode力扣题目111:多种算法对比实现二叉树的最小深度

作者介绍:10年大厂数据\经营分析经验,现任大厂数据部门负责人。
会一些的技术:数据分析、算法、SQL、大数据相关、python
欢迎加入社区:码上找工作
作者专栏每日更新:
LeetCode解锁1000题: 打怪升级之旅
python数据分析可视化:企业实战案例
python源码解读
程序员必备的数学知识与应用

题目描述

给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量。注意:叶子节点是指没有子节点的节点。

示例

示例

输入:

    3/ \9  20/  \15   7

输出:2 (根节点到节点 9 的路径最短)

方法一:递归深度优先搜索(DFS)

解题步骤
  1. 递归终止条件:如果当前节点为空,则返回无穷大(表示没有子节点)。
  2. 递归左右子树:计算左子树和右子树的最小深度。
  3. 计算当前节点的最小深度:当前节点的最小深度为左右子树的最小深度加一。
Python 示例
class TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = rightdef minDepth(root):"""计算二叉树的最小深度:param root: TreeNode, 二叉树的根节点:return: int, 最小深度"""if not root:return 0left = minDepth(root.left)right = minDepth(root.right)# 如果左或右子树为空,应返回非空子树的深度if not root.left or not root.right:return max(left, right) + 1return min(left, right) + 1
算法分析
  • 时间复杂度:(O(n)),每个节点访问一次。
  • 空间复杂度:(O(h)),递归栈的深度,其中 (h) 是树的高度。
    方法一的基本思路是使用深度优先搜索(DFS)递归地检查每个节点的左右子树的最小深度。虽然这种方法直观易懂,但存在重复计算和不必要的深度遍历问题,尤其是在遇到高度不平衡的树时。我们可以通过一些改进来优化这种方法。

方法一改进:优化的DFS

改进点
  1. 提前终止:在发现当前节点的一个子树深度已经小于另一个子树时,可以提前终止对该较深子树的深度计算。这样做可以减少不必要的递归调用。
  2. 缓存结果:对于每个节点的左右子树深度,可以使用哈希表或数组缓存其结果,避免重复计算。
Python 示例
class TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = rightdef minDepth(root):from functools import lru_cache@lru_cache(None)  # 缓存节点深度计算结果def depth(node):if not node:return float('inf')  # 空节点返回无穷大,表示不可达if not node.left and not node.right:return 1  # 叶子节点深度为1# 使用缓存结果,避免重复计算left_depth = depth(node.left)right_depth = depth(node.right)# 提前终止,如果一个子树深度明显小于另一个,不继续计算较大深度子树return min(left_depth, right_depth) + 1if not root:return 0return depth(root)
算法分析
  • 时间复杂度:通过缓存优化后,每个节点最多被计算一次,因此时间复杂度为 (O(n))。
  • 空间复杂度:因为增加了缓存,所以空间复杂度可能稍高,但在最坏情况下仍然为 (O(h)),其中 (h) 是树的高度,对应于递归栈的最大深度。
优劣势比较
  • 优点
    • 减少了不必要的计算,提高了效率。
    • 通过缓存机制,避免了重复计算相同节点的深度。
  • 缺点
    • 代码复杂度略有增加,需要理解缓存机制。
    • 空间开销可能略大,因为要存储每个节点的计算结果。

通过这种改进,DFS 方法不仅变得更加高效,而且也避免了在不平衡树上的性能陷阱。这使得它更加适用于大规模或深度较大的树结构的场景。

方法二:迭代广度优先搜索(BFS)

解题步骤
  1. 使用队列:利用队列存储每层的节点及其深度。
  2. 层级遍历:遍历每个节点,如果是叶子节点,直接返回其深度。
  3. 更新队列:将节点的子节点入队。
Python 示例
from collections import dequedef minDepth(root):if not root:return 0queue = deque([(root, 1)])  # 存储节点及其深度while queue:node, depth = queue.popleft()if not node.left and not node.right:return depthif node.left:queue.append((node.left, depth + 1))if node.right:queue.append((node.right, depth + 1))
算法分析
  • 时间复杂度:(O(n)),每个节点至多访问一次。
  • 空间复杂度:(O(n)),在最坏的情况下,队列中需要存储所有节点。

方法二使用的是广度优先搜索(BFS)来确定二叉树的最小深度。它通过迭代方式检查每一层的节点,直到找到第一个叶子节点,然后立即返回这个叶子节点的深度。这个方法的主要优点是它不必检查所有的节点,尤其是在一个高度不平衡的树中,它可以更快地找到最浅的叶子节点。尽管如此,我们仍然可以对其进行一些改进,以提高其效率和可用性。

方法二改进:优化的BFS

改进点
  1. 避免使用额外的深度存储:在当前的实现中,每个节点及其对应的深度都存储在队列中。我们可以优化这一点,通过在每一轮循环开始时记录队列的长度,从而避免存储每个节点的深度。
  2. 更早的终止条件:在找到第一个叶子节点后,可以立即退出循环,而不是等待当前层的所有节点都被检查完。
Python 示例
from collections import dequeclass TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = rightdef minDepth(root):if not root:return 0queue = deque([root])depth = 0  # 初始化深度为0while queue:depth += 1  # 开始新的一层,深度加1for _ in range(len(queue)):  # 遍历当前层的所有节点node = queue.popleft()if not node.left and not node.right:  # 找到第一个叶子节点return depthif node.left:queue.append(node.left)if node.right:queue.append(node.right)return depth  # 在所有节点都有子节点的情况下返回最终深度
算法分析
  • 时间复杂度:在最坏情况下,即遍历到最后一层才找到叶子节点,时间复杂度仍为 (O(n))。
  • 空间复杂度:空间复杂度主要取决于队列中存储的节点数,最坏情况下,队列中可能包含 (n/2) 个节点(最后一层的节点数),因此空间复杂度为 (O(n))。
优劣势比较
  • 优点
    • 立即找到叶子节点后就结束,避免了不必要的计算。
    • 不需要额外存储节点深度,简化了代码。
  • 缺点
    • 在极端情况下(例如,当树高度非常大时),空间复杂度可能仍然较高。

通过这种改进,BFS 方法更加高效和直观,尤其是在处理大型数据集时,这种方法能快速找到最小深度,而无需深入遍历树的所有部分。这使得它在实际应用中更加实用,尤其是在数据结构动态变化较大的环境中。

应用示例

这些方法在需要快速确定数据结构(如游戏、网络路由、社交网络的层级结构)中的最小路径或深度时非常有用。

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

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

相关文章

WPF 图片显示某一部分区域

效果图&#xff1a; 代码&#xff1a; <Image Width"32"HorizontalAlignment"Right"Height"32"Source"../../Resources/Images/BLUEWOLF.jpg"><Image.Clip><PathGeometry><PathFigure StartPoint"32,32&quo…

苍穹外卖项目---------收获以及改进(5-6天)

①HttpClient 核心作用&#xff1a;在java编码中发送http请求 第一步&#xff1a;引入依赖 第二步&#xff1a;使用封装一个工具类 package com.sky.utils;import com.alibaba.fastjson.JSONObject; import org.apache.http.NameValuePair; import org.apache.http.client.co…

Scrapy框架快速入门指南

Scrapy框架快速入门指南 在数据驱动的世界中&#xff0c;快速而高效地抓取数据变得尤为重要。Scrapy是一个快速、简单但功能强大的爬虫框架&#xff0c;能够满足数据抓取的各种需求。今天&#xff0c;我们将快速入门Scrapy&#xff0c;了解如何使用它抓取和提取数据。 目录 …

【北京迅为】《iTOP-3588开发板源码编译手册》-第4章 Android12/Linux设备树简介

RK3588是一款低功耗、高性能的处理器&#xff0c;适用于基于arm的PC和Edge计算设备、个人移动互联网设备等数字多媒体应用&#xff0c;RK3588支持8K视频编解码&#xff0c;内置GPU可以完全兼容OpenGLES 1.1、2.0和3.2。RK3588引入了新一代完全基于硬件的最大4800万像素ISP&…

Docker 容器连接:构建安全高效的容器化网络生态

Docker容器连接详解 在 Docker 中&#xff0c;容器之间可以通过网络连接来实现通信和交互。下面详细解释了 Docker 容器连接的常用命令、示例、应用场景、注意事项以及总结&#xff1a; 常用命令 创建网络&#xff08;create network&#xff09;&#xff1a;使用 docker net…

微信小程序03: 获取不限制的小程序二维码

全文目录,一步到位 1.前言简介1.1 专栏传送门1.1.1 上文小总结1.1.2 上文传送门 2. 获取不限制二维码操作2.1 准备工作2.1.1 请先复制00篇的统一封装代码2.1.2 修改配置文件中的参数 2.2 具体代码使用与注释如下2.2.1 业务代码如下2.2.2 代码解释(一)[无需复制]2.2.3 创建Base6…

html--瀑布效果

<!doctype html> <html> <head> <meta charset"utf-8"> <title>瀑布效果</title><style> body {background: #222;color: white;overflow:hidden; }#container {box-shadow: inset 0 1px 0 #444, 0 -1px 0 #000;height: 1…

Sakura编辑器

1、sakura左右上下分屏不让联动设置

Java中Maven的依赖管理

依赖介绍 是指当前项目运行所需要的jar包&#xff0c;一个项目中可以引入多个依赖 配置 在pom.xml中编写<dependencies>标签 在<dependencies>中使用<dependency>引入标签 定义坐标的groupId、rtifactId、version 点击刷新按钮、引入新坐标 例如引入下…

You Only Look at Once for Real-Time and Generic Multi-Task

摘要 高精度、轻量级和实时响应是实现自动驾驶的三个基本要求。在这项研究中&#xff0c;我们介绍了一个自适应、实时和轻量级的多任务模型&#xff0c;旨在同时解决目标检测、可行驶区域分割和车道线分割任务。具体来说&#xff0c;我们开发了一个具有统一和精简的分割结构的…

从零开始:搭建PXE远程批量安装服务器

在大规模服务器部署时&#xff0c;面对成百上千台服务器&#xff0c;通过手动插入光盘或者USE驱动器来安装操作系统无比繁琐&#xff0c;让大量工程师在现场挨个安装系统也不切实际&#xff0c;PXE的出现使得网络远程批量自动安装和配置操作系统成为现实。 什么是PXE&#xff1…

nginx模型设计和进程讲解

一. Nginx进程模型解析 1. master主进程 和 worker工作进程 [rootlocalhost sbin]# ps -ef|grep nginx root 15411 1 0 21:08 ? 00:00:00 nginx: master process ./nginx nobody 15412 15411 0 21:08 ? 00:00:00 nginx: worker process root…

YzmCMS 7.0任意函数调用RCE 漏洞研究分析

YzmCMS是一款基于YZMPHP开发的一套轻量级开源内容管理系统,YzmCMS简洁、安全、开源、免费,可运行在Linux、Windows、MacOSX、Solaris等各种平台上,专注为公司企业、个人站长快速建站提供解决方案。 YzmCMS 某些接口调用了 db_pdo类的where方法 导致了远程命令执行漏洞&#xf…

C语言实现面向对象

一、引言 面向对象编程&#xff08;OOP&#xff09;是一种程序设计范型&#xff0c;它使用“对象”来设计应用程序和系统的结构和行为。虽然C语言本身并不直接支持面向对象编程&#xff0c;但我们可以使用结构体&#xff08;struct&#xff09;和 函数指针&#xff08;function…

上市公司财务困境模型​MertonDD、OScore、RLPM、ZScore四种模型​(1992-2022年)

01、数据介绍 上市公司财务困境模型是用于预测和评估上市公司是否可能陷入财务困境的一种模型。这个模型通常基于一系列的财务比率和其他相关变量&#xff0c;通过统计分析方法来构建。​ 数据名称&#xff1a;上市公司财务困境模型MertonDD、OScore、RLPM、ZScore五种模型 …

vue2 阻止控制台报错

在Vue 2中&#xff0c;如果你想要阻止控制台中的某些错误报告&#xff0c;你可以使用Vue.config.errorHandler来全局处理错误&#xff0c;从而避免控制台输出这些错误。 例如&#xff0c;你可以在Vue应用的入口文件&#xff08;比如main.js&#xff09;中添加以下代码&#xf…

电脑提示mfc140u.dll文件丢失了?怎么快速修复mfc140u.dll文件

当你的电脑提示你的mfc140u.dll文件丢失了&#xff0c;那么就要小心了&#xff0c;可能你的某些程序出问题了&#xff01;这时候需要我们去进行相关的修复&#xff0c;只有修复了这个mfc140u.dll文件&#xff0c;才能正常的使用某些程序。下面一起来了解一下mfc140u.dll文件吧。…

download_file、download

download_file源码 def download_file(url: str, fname: str, chunk_size1024):"""Helper function to download a file from a given url"""resp requests.get(url, streamTrue)total int(resp.headers.get("content-length", 0))…

C++中erase函数的用法

在C中&#xff0c;erase函数用于从容器中删除一个或一系列元素。它通常用于删除容器中的指定位置的元素或特定值的元素。 erase函数通常有两种用法&#xff1a; 删除指定位置的元素&#xff1a;erase(iterator position) 这种用法会删除容器中迭代器position指向的元素。 st…

uni-app安卓本地打包个推图标配置

如果什么都不配置&#xff0c;默认的就是个推小鲸鱼图标 默认效果 配置成功效果 个推图标配置 新建目录 drawable-hdpi、drawable-ldpi、drawable-mdpi、drawable-xhdpi、drawable-xxhdpi、drawable-xxxhdpi 目录中存放图标 每个目录中存放对应大小的图标&#xff0c;大图…