Python算法题集_在排序数组中查找元素的第一个和最后一个位置

Python算法题集_在排序数组中查找元素的第一个和最后一个位置

  • 题34:在排序数组中查找元素的第一个和最后一个位置
  • 1. 示例说明
  • 2. 题目解析
    • - 题意分解
    • - 优化思路
    • - 测量工具
  • 3. 代码展开
    • 1) 标准求解【二分法+两次左边界】
    • 2) 改进版一【二分法+左右边界】
    • 3) 改进版二【第三方模块】
  • 4. 最优算法
  • 5. 相关资源

本文为Python算法题集之一的代码示例

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

1. 示例说明

  • 给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

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

    你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

    示例 1:

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

    示例 2:

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

    示例 3:

    输入:nums = [], target = 0
    输出:[-1,-1]
    

    提示:

    • 0 <= nums.length <= 105
    • -109 <= nums[i] <= 109
    • nums 是一个非递减数组
    • -109 <= target <= 109

2. 题目解析

- 题意分解

  1. 本题是在已排序列表中查找目标数值的左边界和右边界
  2. 最快方式就是二分法

- 优化思路

  1. 通常优化:减少循环层次

  2. 通常优化:增加分支,减少计算集

  3. 通常优化:采用内置算法来提升计算速度

  4. 分析题目特点,分析最优解

    1. 可以通过查找左边界的方式执行,查找目标的左边界+查找目标+1的左边界

    2. 可以通过查找左边界、右边界的方式执行

    3. 可以考虑使用排序列表操作模块bisect

- 测量工具

  • 本地化测试说明:LeetCode网站测试运行时数据波动很大【可把页面视为功能测试】,因此需要本地化测试解决数据波动问题
  • CheckFuncPerf(本地化函数用时和内存占用测试模块)已上传到CSDN,地址:Python算法题集_检测函数用时和内存占用的模块
  • 本题本地化超时测试用例自己生成,详见章节【最优算法】,代码文件包含在【相关资源】中

3. 代码展开

1) 标准求解【二分法+两次左边界】

二分法查询目标值左边界和目标+1左边界

页面功能测试,性能一般,超过78%在这里插入图片描述

import CheckFuncPerf as cfp

class Solution:
 def searchRange_base(self, nums, target):
     def searchbig(target: int) -> int:
         ileft, iright = 0, len(nums)
         while ileft < iright:
             imid = ileft + ((iright - ileft) >> 1)
             if nums[imid] > target:
                 iright = imid
             else:
                 ileft = imid + 1
         return iright
     istart = searchbig(target - 1)
     if istart == len(nums) or nums[istart] != target:
         return [-1, -1]
     iend = searchbig(target)
     return [istart, iend - 1]

aSolution = Solution()
result = cfp.getTimeMemoryStr(aSolution.searchRange_base, nums, itarget)
print(result['msg'], '执行结果 = {}'.format(result['result']))
 
# 运行结果
函数 searchRange_base 的运行时间为 0.00 ms;内存使用量为 4.00 KB 执行结果 = [33333333, 33333334]

2) 改进版一【二分法+左右边界】

二分法查询目标值左边界和右边界

页面功能测试,马马虎虎,超过56%在这里插入图片描述

import CheckFuncPerf as cfp

class Solution:
 def searchRange_ext1(self, nums, target):
     result = [-1, -1]
     def searchbymode(ileft, iright, modeflag):
         while ileft <= iright:
             imid = (ileft + iright) // 2
             if nums[imid] == target:
                 if modeflag:
                     result[0] = imid
                     iright = imid - 1
                 else:
                     result[1] = imid
                     ileft = imid + 1
             elif nums[imid] > target:
                 iright = imid - 1
             else:
                 ileft = imid + 1
     searchbymode(0, len(nums) - 1, True)
     searchbymode(0, len(nums) - 1, False)
     return result

aSolution = Solution()
result = cfp.getTimeMemoryStr(aSolution.searchRange_ext1, nums, itarget)
print(result['msg'], '执行结果 = {}'.format(result['result']))
 
# 运行结果
函数 searchRange_ext1 的运行时间为 0.00 ms;内存使用量为 4.00 KB 执行结果 = [33333333, 33333334]

3) 改进版二【第三方模块】

使用排序列表操作模块bisect来查找左右边界

页面功能测试,马马虎虎,超过42%在这里插入图片描述

import CheckFuncPerf as cfp

class Solution:
 def searchRange_ext2(self, nums, target):
     from bisect import bisect_left, bisect_right
     ileft = bisect_left(nums, target)
     if ileft >= len(nums):
         return [-1, -1]
     if nums[ileft] != target:
         return [-1, -1]
     if ileft == len(nums)-1:
         return [ileft, ileft]
     if nums[ileft+1] != target:
         return [ileft, ileft]
     iright = bisect_right(nums[ileft+1:], target)
     return [ileft, ileft+iright]

aSolution = Solution()
result = cfp.getTimeMemoryStr(aSolution.searchRange_ext2, nums, itarget)
print(result['msg'], '执行结果 = {}'.format(result['result']))
 
# 运行结果
函数 searchRange_ext2 的运行时间为 680.67 ms;内存使用量为 4.00 KB 执行结果 = [33333333, 33333334]

4. 最优算法

根据本地日志分析,最优算法为第1种方式【二分法+两次左边界】、第2种方式【二分法+左右边界】并列

本题测试数据,似乎能推出以下结论:

  1. 二分法查询性能非常夸张,简直是瞬间定位【1亿的数组,1毫秒定位】
  2. 第三方模块的算法估计是进行了切片操作
import random
ilen, istart = 100000000, 0
nums = [0 for x in range(ilen)]
for iIdx in range(ilen):
    istart += random.randint(0, 3)
    nums[iIdx] = istart
itarget = nums[ilen // 3]
aSolution = Solution()
result = cfp.getTimeMemoryStr(aSolution.searchRange_base, nums, itarget)
print(result['msg'], '执行结果 = {}'.format(result['result']))
result = cfp.getTimeMemoryStr(aSolution.searchRange_ext1, nums, itarget)
print(result['msg'], '执行结果 = {}'.format(result['result']))
result = cfp.getTimeMemoryStr(aSolution.searchRange_ext2, nums, itarget)
print(result['msg'], '执行结果 = {}'.format(result['result']))

# 算法本地速度实测比较
函数 searchRange_base 的运行时间为 0.00 ms;内存使用量为 4.00 KB 执行结果 = [33333333, 33333334]
函数 searchRange_ext1 的运行时间为 0.00 ms;内存使用量为 4.00 KB 执行结果 = [33333333, 33333334]
函数 searchRange_ext2 的运行时间为 680.67 ms;内存使用量为 4.00 KB 执行结果 = [33333333, 33333334]

5. 相关资源

本文代码已上传到CSDN,地址:Python算法题源代码_LeetCode(力扣)_在排序数组中查找元素的第一个和最后一个位置

一日练,一日功,一日不练十日空

may the odds be ever in your favor ~

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

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

相关文章

linux安装ngnix完整步骤(支持centos/银河麒麟操作系统)

linux安装ngnix&#xff08;支持centos/银河麒麟操作系统&#xff09; 本次操作系统安装ngnix采用离线或在线安装方式&#xff0c;离线就是不联网环境&#xff0c;在线则是联网环境&#xff1b;支持centos7或centos8或国产操作系统&#xff08;银河麒麟高级服务器操作系统&…

VUE3项目学习系列--项目基础配置(四)

一、环境变量配置 项目开发过程中会经历开发环境、测试环境、生产环境三种状态&#xff0c;对与环境变量的配置需求不同&#xff0c;因此需要在项目中进行环境变量的配置。 1.在项目根目录下添加如下3个文件 .env.development.env.production.env.test 文件中输入对应的配置…

Turbo C++编译并运行 C语言程序

Turbo C编译并运行 C语言程序 安装和下载Windows 版Turbo CTurbo C编译和运行 C 程序1.打开Turbo C2.新建C语言程序3.保存C语言程序4.命名C语言程序5.编译C语言程序6.运行C语言程序7.运行C语言程序成功 Turbo C是什么&#xff1f;什么是编译器&#xff1f;Turbo C/C 的超凡价值…

算法---双指针练习-4(盛水最多的容器)

题目 1. 题目解析2. 讲解算法原理3. 编写代码 1. 题目解析 题目地址&#xff1a;盛水最多的容器 2. 讲解算法原理 算法的主要思路是使用双指针的方法&#xff0c;通过不断调整指针的位置来计算面积&#xff0c;并更新最大面积。具体步骤如下&#xff1a; 初始化左指针x为数组…

Java二叉树 (2)

&#x1f435;本篇文章将对二叉树的一些基础操作进行梳理和讲解 一、操作简述 int size(Node root); // 获取树中节点的个数int getLeafNodeCount(Node root); // 获取叶子节点的个数int getKLevelNodeCount(Node root,int k); // 获取第K层节点的个数int getHeight(Node r…

基于springboot+vue实现早餐店点餐系统项目【项目源码+论文说明】计算机毕业设计

基于springbootvue实现早餐店点餐系统演示 摘要 多姿多彩的世界带来了美好的生活&#xff0c;行业的发展也是形形色色的离不开技术的发展。作为时代进步的发展方面&#xff0c;信息技术至始至终都是成就行业发展的重要秘密。不论何种行业&#xff0c;大到国家、企业&#xff0…

Python实例☞组织结构案例

实例一&#xff1a; ❶要求☞ 使用while循环模拟用户登录 ❷程序代码☞ i1 while i<4: nameinput("请输入您的姓名&#xff1a;") passwardinput("请输入你的密码&#xff1a;") if name"鯨殤" and passward"88888": print(&quo…

VLAN FAQ

如何快速查看所有接口的接口类型和缺省VLAN&#xff1f; 可通过命令display port vlan查看到设备上所有接口的接口类型和缺省VLAN。例如&#xff1a; V200R005及后续版本<HUAWEI> display port vlan Port Link Type PVID Trunk VLAN List --…

高效提升控制效率 | 基于ACM32 MCU的LED灯箱控制器方案

LED灯箱上各种文字、图案有序跳跃、交替辉映&#xff0c;产生强烈的视觉冲击力&#xff0c;被广泛应用于商场、美容美发、宾馆、娱乐场所等地方。 锁存器的工作原理 在LED和数码管显示方面&#xff0c;要维持一个数据的显示&#xff0c;往往要持续的快速的刷新。尤其是在四段八…

HTML 学习笔记(四)图片

<!--通过图片标签"<img src "图片路径">"来调用图片在网页中进行显示--> <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthd…

物联网开发 11 ESP32 和 ESP8266 比较有哪些不同?

首先&#xff0c;ESP32和ESP8266都是性价比非常高的Wi-Fi模块&#xff0c;都非常适合用来做物联网&#xff08;IoT&#xff09;领域的项目。两款芯片都属于32位处理器&#xff0c;ESP32是双核160MHz至240MHz CPU&#xff0c;而ESP8266是单核处理器&#xff0c;运行频率为80MHz。…

Gradio快速搭建机器学习模型的wedui展示用户界面/深度学习网页模型部署

Gradio 快速开始 Installation 安装Building Your First DemoSharing Your Demo 分享您的演示 官网 Gradio 是一个开源 Python 包&#xff0c;可让您快速为机器学习模型、API 或任何任意 Python 函数构建演示或 Web 应用程序。然后&#xff0c;您可以使用 Gradio 的内置共享功…

熬过了劫数,生活将会越过越好

人情无常&#xff0c;看开方自在&#xff1b;得失无常&#xff0c;随缘半称心&#xff1b;生命无常&#xff0c;心宽人自安。人生无常&#xff0c;才是世间常态。生命的长短和意外一样&#xff0c;是一件突如其来的事情&#xff0c;我们都无法控制。死亡面前&#xff0c;人永远…

LLM 推理优化探微 (3) :如何有效控制 KV 缓存的内存占用,优化推理速度?

编者按&#xff1a; 随着 LLM 赋能越来越多需要实时决策和响应的应用场景&#xff0c;以及用户体验不佳、成本过高、资源受限等问题的出现&#xff0c;大模型高效推理已成为一个重要的研究课题。为此&#xff0c;Baihai IDP 推出 Pierre Lienhart 的系列文章&#xff0c;从多个…

PHP学习笔记

PHP学习笔记 一.准备环境二.安装Apache添加环境变量 三.安装PHP添加环境变量 配置 apache 支持 php四.安装Mysql配置环境MySQL的访问流程php连接mysql 五虚拟主机虛拟主机的分类搭建基于域名的虚拟主机 一.准备环境 下载Apache 和PHP 安装mysql 特殊IP&#xff1a;127.0.0.1 代…

Java高频面试之集合篇

Java 中常用的容器有哪些&#xff1f; ArrayList 和 LinkedList 的区别&#xff1f; ArrayList 是基于数组实现的,LinkedList 是基于链表实现的. ArrayList实现了RandomAccess接口,可基于下标访问. LinkedList 实现了Deque /dek/,可以当做双端队列使用. 插入效率对比 如果从头部…

Java共享问题 、synchronized 线程安全分析、Monitor、wait/notify

文章目录 1.共享带来的问题1.1 临界区 Critical Section1.2 竞态条件 Race Condition 2. synchronized语法及理解2.1 方法上的 synchronized 3.变量的线程安全分析3.1.成员变量和静态变量是否线程安全&#xff1f;3.2.局部变量是否线程安全&#xff1f;3.2.1 局部变量线程安全分…

NIO学习总结(二)——Selector、FileLock、Path、Files、聊天室实现

一、Selector 1.1 Selector简介 1.1.1 Selector 和 Channel的关系 Selector 一般称为选择器 &#xff0c;也可以翻译为 多路复用器 。 它是 Java NIO 核心组件中的一个&#xff0c;用于检查一个或多个 NIO Channel&#xff08;通道&#xff09;的状态是否处于可读、可写。由…

ubuntu20.04环境搭建:etcd+patroni+pgbouncer+haproxy+keepalived的postgresql集群方案

搭建基于etcdpatronipgbouncerhaproxykeepalived的postgresql集群方案 宿主机操作系统:ubuntu20.04 使用kvm搭建虚拟环境(如没有安装kvm&#xff0c;请先自行安装kvm) 1、安装kvm服务 ①、查看虚拟支持 如果CPU 支持硬件虚拟化则输出结果大于0&#xff0c;安装kvm-ok命令检…

蓝桥省赛倒计时 35 天-双指针

双指针介绍 双指针算法是一种常用的算法技巧&#xff0c;它通常用于在数组或字符串中进行快速查找、匹配、排序或移动操作。 pointer 双指针并非真的用指针实现&#xff0c;一般用两个变量来表示下标&#xff08;在后面都用指针来表示&#xff09;。 双指针算法使用两个指针在数…