LeetCode题目34:在排序数组中查找元素的第一个和最后一个位置【python】

问题描述

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

你的算法时间复杂度必须是 O(log n) 级别。

如果数组中不存在目标值,返回 [-1, -1]

示例 1

输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]

示例 2

输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]

解题思路

这个问题可以通过二分查找算法来解决,以达到题目要求的 O(log n) 时间复杂度。我们可以使用两次二分查找:一次查找目标值 target 的起始位置,另一次查找目标值的结束位置。

方法一:直接二分查找

这种方法在同一个二分查找过程中确定起始和结束位置,避免了重复查找和多余的判断。

代码实现
def searchRange(nums, target):
    def binary_search(left, right, find_start):
        index = -1
        while left <= right:
            mid = (left + right) // 2
            if nums[mid] > target:
                right = mid - 1
            elif nums[mid] < target:
                left = mid + 1
            else:
                index = mid
                if find_start:
                    right = mid - 1
                else:
                    left = mid + 1
        return index

    start = binary_search(0, len(nums) - 1, True)
    if start == -1:
        return [-1, -1]  # Early exit if `target` is not found
    end = binary_search(0, len(nums) - 1, False)
    return [start, end]

# 示例
print(searchRange([5,7,7,8,8,10], 8))  # 输出: [3, 4]
print(searchRange([5,7,7,8,8,10], 6))  # 输出: [-1, -1]
算法图解

以下是一个针对数组 [5,7,7,8,8,10] 查找 8 的具体流程的 ASCII 图解:

数组: [5, 7, 7, 8, 8, 10]
目标值: 8
二分查找过程的 ASCII 图解
初始数组设置:
索引:   0   1   2   3   4   5
值:   [5,  7,  7,  8,  8, 10]

初始指针:
左指针 (L) -> 0                    右指针 (R) -> 5

步骤 1: 计算中间点:
中间点 (M) -> (0+5)/2 = 2

   L     M           R
   |     |           |
  [5,    7,    7,    8,    8,   10]
        中值 < 目标值, 左指针移动到中点右侧

步骤 2: 移动左指针:
左指针 (L) -> 3

   L                 R
   |                 |
  [5,    7,    7,    8,    8,   10]
        新中点 (M) -> (3+5)/2 = 4

步骤 3: 计算新中点:
中间点 (M) -> 4
   L     M           R
   |     |           |
  [5,    7,    7,    8,    8,   10]
        中值 == 目标值, 展开查找完整范围

步骤 4: 扩展查找开始和结束位置:
   从位置3开始, 向左检查 nums[3-1] 是否为8, 向左递减找到开始
   开始位置 -> 3

   从位置4开始, 向右检查 nums[4+1] 是否为8, 向右递增找到结束
   结束位置 -> 4

最终结果: [3, 4]
ASCII 图解说明
  1. 初始设置:初始时,左指针位于数组起始位置(0),右指针位于数组末端(5)。

  2. 首次计算中间点:通过表达式 (左指针 + 右指针) / 2 计算中间点。中间点(2)的值为7,小于目标值8,所以将左指针移动到中点的右侧。

  3. 移动左指针:左指针更新至索引3,重新计算中间点。

  4. 计算新中间点:新的中间点位置是4,数值与目标值相等,现在需要确定该目标值的完整范围。

  5. 扩展查找范围

    • 查找开始位置:从索引3开始向左扩展,直到数组元素不等于8。
    • 查找结束位置:从索引4开始向右扩展,直到数组元素不等于8。

这种方法不仅利用了二分查找的高效性在对数时间内找到结果,还通过额外的线性扫描处理来定位目标值的完整范围,适合解决需要快速解答范围查询的问题。

方法二:优化的二分查找

分别进行两次二分查找:第一次找到第一个不小于 target 的位置(可能的开始位置),第二次找到第一个大于 target 的位置减一(可能的结束位置)。

代码实现
def searchRange(nums, target):
    def findFirstPosition():
        left, right = 0, len(nums) - 1
        while left <= right:
            mid = (left + right) // 2
            if nums[mid] < target:
                left = mid + 1
            else:
                right = mid - 1
        return left

    def findLastPosition():
        left, right = 0, len(nums) - 1
        while left <= right:
            mid = (left + right) // 2
            if nums[mid] <= target:
                left = mid + 1
            else:
                right = mid - 1
        return right

    start = findFirstPosition()
    end = findLastPosition()

    # Check if `target` is out of bounds
    if start <= end and 0 <= start < len(nums) and nums[start] == target and nums[end] == target:
        return [start, end]
    return [-1, -1]

# 示例
print(searchRange([5,7,7,8,8,10], 8))  # 输出: [3, 4]
print(searchRange([5,7,7,8,8,10], 6))  # 输出: [-1, -1]

算法分析

通过表格来展示这两种方法的时间复杂度、空间复杂度以及它们的主要优势和劣势。

特征方法一:直接二分查找方法二:优化的二分查找
时间复杂度O(log n)O(log n)
空间复杂度O(1)O(1)
优势- 简化逻辑,只需一个二分查找函数,通过传入参数控制查找开始或结束。
- 直观易懂,适用于对二分查找流程有清晰理解的情况。
- 代码结构清晰,将寻找开始位置和结束位置的任务分开处理,易于维护。
- 更符合一般二分查找的模式,逻辑分明,减少了错误和调试时间。
劣势- 逻辑在单个函数中可能稍显复杂,尤其是在处理边界条件时。
- 如果未来需要修改或扩展查找逻辑,可能需要重写较多代码。
- 实现两个函数,代码行数较多。
- 如果问题场景不需要严格分离起始和结束位置查找,可能会导致轻微的效率下降。

总结

两种方法都利用二分查找来定位目标值的起始和结束位置,但第二种方法通过分离查找起始位置和结束位置的逻辑,使得代码更为清晰和易于管理。每种方法都符合题目的时间复杂度要求,具体使用哪种取决于个人偏好

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

k-means聚类算法的MATLAB实现及可视化

K-means算法是一种无监督学习算法&#xff0c;主要用于数据聚类。其工作原理基于迭代优化&#xff0c;将数据点划分为K个集群&#xff0c;使得每个数据点都属于最近的集群&#xff0c;并且每个集群的中心&#xff08;质心&#xff09;是所有属于该集群的数据点的平均值。以下是…

中文核心计算机视觉项目分享:多通道注意力机制得农业作物图像识别检测-完整代码+论文

创新点&#xff1a; 在苹果数据集中&#xff0c;存在遮挡、不同角度的拍摄、光照变化等问题&#xff0c;导致目标检测的性能下降。为了解决这些问题&#xff0c;提出智能感知优化网络和多路径特征融合网络。 智能感知优化网络&#xff1a;帮助模型更好地关注感兴趣的目标区域&…

电商技术揭秘二十七:跨境电商物流解决方案

相关系列文章 电商技术揭秘一&#xff1a;电商架构设计与核心技术 电商技术揭秘二&#xff1a;电商平台推荐系统的实现与优化 电商技术揭秘三&#xff1a;电商平台的支付与结算系统 电商技术揭秘四&#xff1a;电商平台的物流管理系统 电商技术揭秘五&#xff1a;电商平台…

C语言学习笔记之指针(二)

指针基础知识&#xff1a;C语言学习笔记之指针&#xff08;一&#xff09;-CSDN博客 目录 字符指针 代码分析 指针数组 数组指针 函数指针 代码分析&#xff08;出自《C陷阱和缺陷》&#xff09; 函数指针数组 指向函数指针数组的指针 回调函数 qsort() 字符指针 一…

试用模方时,系统一直提示“未找到有效配置文件” ,是需要安装3dsmax吗 ?

问题如图 把文件放在认证管理服务安装目录下即可。&#xff08;注&#xff1a;因平台限制&#xff0c;需要文件的直接后台私信即可哦&#xff09; 模方是一款针对实景三维模型的冗余碎片、水面残缺、道路不平、标牌破损、纹理拉伸模糊等共性问题研发的实景三维模型修复编辑软件…

软考 - 系统架构设计师 - 数据架构真题

问题 1&#xff1a; (相当于根据题目中提到的 4 点&#xff0c;说一下关系型数据库的缺点) &#xff08;1&#xff09;.用户数量的剧增导致并发负载非常高&#xff0c;往往会达到每秒上万次读写请求。关系数据库应付每秒上万次的 SQL 查询还勉强可以&#xff0c;但是应付上万…

车载摄像头夜景增强技术解决方案,解锁高质量夜间视觉体验

随着汽车智能化的快速发展&#xff0c;车载摄像头已成为驾驶辅助系统的核心组件。尤其在夜间行驶时&#xff0c;摄像头所捕捉的画面质量直接关系到驾驶者的安全感知和行车决策。然而&#xff0c;传统的车载摄像头在夜间往往面临噪声多、画质差等挑战&#xff0c;难以满足用户对…

goland2024安装包(亲测可用)

目录 一、软件简介 二、软件下载 一、软件简介 Goland 是一款由 JetBrains 公司开发的集成开发环境&#xff08;IDE&#xff09;&#xff0c;专门用于 Go 语言的开发。它提供了丰富的功能和工具&#xff0c;帮助开发者更高效地编写、调试和管理 Go 语言项目。 功能特点&#x…

什么是Rust语言?探索安全系统编程的未来

&#x1f680; 什么是Rust语言&#xff1f;探索安全系统编程的未来 文章目录 &#x1f680; 什么是Rust语言&#xff1f;探索安全系统编程的未来摘要引言正文&#x1f4d8; Rust语言简介&#x1f31f; 发展历程&#x1f3af; Rust的技术意义和优势&#x1f4e6; Rust解决的问题…

基于逐笔数据合成高频订单簿:DolphinDB 订单簿引擎

订单簿是交易市场上买卖双方正在报价的不同价格的列表。订单簿快照反应了特定时刻市场上的交易意图&#xff0c;比如交易活跃的证券标的往往有着密集的订单簿。订单簿快照对量化金融的交易策略、风险管理和市场分析等方面都具有重要意义。 通常交易所可以提供实时和历史的行情…

无界系统实战课:全体系落地无界改版后选择、出价、高投产做付费引流-38节

课程内容&#xff1a; 001.01、如何快速学习无界推广(新学员先听).mp4 002.02、如何快速上手和适应无界(老学员先听).mp4 003.03、无界推广在运营中的作用(必听).mp4 004.04、无界多工具如何选择(必听).mp4 005.05、自定义出价、控成本、最大化底层逻辑和选择(必听).mp4 …

postgres插件部署+函数开发 - pl/java安装(centos7)

一、安装postgres sudo yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm sudo yum install -y postgresql11-server sudo /usr/pgsql-11/bin/postgresql-11-setup initdb sudo systemctl enable postg…

stable diffusion--小白学习步骤

1.看一下Unet网络的讲解_哔哩哔哩_bilibili&#xff0c;了解Unet网络 2.看一下【生成式AI】Diffusion Model 原理剖析 (1/4)_哔哩哔哩_bilibili&#xff0c;起码要看前3/6个视频 3.看一下超详细的扩散模型&#xff08;Diffusion Models&#xff09;原理代码 - 知乎 (zhihu.co…

前端-vue项目debugger调试

一、前言 有的时候接受同事一个项目&#xff0c;用框架不一样&#xff0c;写的也不太规范&#xff0c;那么就需要打断点去学习改项目的流程了。 那么vue项目是如何debugger调试呢&#xff1f; 二、操作 大概理解一下&#xff0c;vue项目启动&#xff0c;大概是先启动框架&am…

nginx 卸载和安装超详细教程

一、前言 由于现在nginx有版本漏洞&#xff0c;所以很多安装过nginx的需要卸载重新安装&#xff0c;没安装过的&#xff0c;切记不要乱安装版本。 OK以上版本切记不能再用了&#xff01; 废话不多说&#xff0c;直接上干货。 二、卸载 1、停止Nginx进程 命令行停止&#xf…

【C++成长记】C++入门 | 类和对象(上) |面向过程和面向对象初步认识、类的引入、类的定义、类的访问限定符及封装

&#x1f40c;博主主页&#xff1a;&#x1f40c;​倔强的大蜗牛&#x1f40c;​ &#x1f4da;专栏分类&#xff1a;C❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 一、面向过程和面向对象初步认识 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步…

【日常记录】【CSS】利用动画延迟实现复杂动画

文章目录 1、介绍2、原理3、代码4、参考链接 1、介绍 对于这个效果而言&#xff0c;最先想到的就是 监听滑块的input事件来做一些操作 ,但是会发现&#xff0c;对于某一个节点的时候&#xff0c;这个样式操作起来比较麻烦 只看这个代码的话&#xff0c;发现他用的是动画&#x…

第47期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以找…

通过超分辨率像素引导的Scribble Walking和逐类对比正则化的弱监督医学图像分割(SC-Ne)论文速读

目录 Weakly Supervised Medical Image Segmentation via Superpixel-Guided Scribble Walking and Class-Wise Contrastive Regularization摘要方法实验结果 Weakly Supervised Medical Image Segmentation via Superpixel-Guided Scribble Walking and Class-Wise Contrastiv…

召唤新版「数据库 GitOps 」体验官,赢取新款 Bytebase 限量周边!

距上一次「产品体验官&#xff5c;基于 GitHub 的数据库 CI/CD」已有一年半了⌛️ Bytebase 于上周发布了 Bytebase 2.15.0 - GitOps 整体升级 &#x1f38a; 全新的 GitOps 体验&#xff0c;更易上手&#xff0c;更简洁&#xff01;&#x1f929; 不管你是否使用过 Byteb…