当前位置: 首页 > news >正文

在排序数组中查找元素的第一个和最后一个位置(Java详解)

一、题目描述

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

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

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

示例:

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

输出:[3, 4]

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

输出:[-1, -1]

输入:nums = [ ],target = 0

输出:[-1, -1]

二、题解

思路分析:

题目要求我们找到出现target的第一个位置和最后一个位置,首先,我们想到可以通过暴力枚举的方法来解决该问题,即遍历数组,并记录target第一次出现和最后一次出现的位置。然而,题目要求我们实现时间复杂度为O(log n)的算法,且题目中给出的数组为非递减的数组,因此,我们可以考虑使用二分查找的方法来解决该问题

由于题目中数据量较小,使用遍历的方法也可以通过该题

遍历代码:

class Solution {public int[] searchRange(int[] nums, int target) {int first = -1;int last = -1;boolean flg = false;//判断是否是第一个位置for (int i = 0; i < nums.length; i++) {//第一个位置if(nums[i] == target && !flg){first = i;flg = true;}//最后一个位置//注意处理特殊情况,即最后一个元素在最后一个位置时,nums[i+1]越界if(nums[i] == target && (i == nums.length - 1 || nums[i+1] != target)){last = i;}}int[] ret = {first,last};return ret;}
}

如何使用二分查找来解决该问题?

题目要求我们找到target在数组中第一次出现和最后一次出现的位置,利用数组非递减的性质

首先我们查找元素的第一个位置:

 我们可通过target将数组分为两部分

其中,左边部分为小于target的元素,右边部分为大于等于target的元素,由于右边区域大于等于target,因此区域最左边的值即为target第一次出现的位置,即右边区域的左端点为所求结果

我们定义left指向0位置,right指向最后一个元素,mid指向中间位置

若mid指向的元素落在右边区间,此时nums[mid]大于等于target,需要更新right的值,由于要找的结果(target第一次出现的位置)在此区间内,即mid所指向的位置可能就是最终结果,因此不能将right更新为mid - 1,而应更新为mid

若mid所指向的元素落在左边区间,此时nums[mid]小于target,需要更新 left 的值,由于要找的结果不在此区间内,因此可将left的结果更新为 mid + 1

 当left和right之间元素为偶数个时,此时中间元素有两个,应该选择哪一个作为中间元素?

由于我们查找的是右边区间内最左边的元素,因此,应该选择左边的元素作为中间元素

若选择右边元素作为中间元素,能够成功查找到结果吗? 

当选择右边元素作为中间元素时,此时会出现死循环的情况,例如: 

 上图中,当选择右边元素作为中间元素时,mid指向的元素落在右边区间,此时将right更新为mid,再求mid,此时mid仍为指向刚才位置,即落在右边区间,此时再次更新right为mid,再次求mid... 从而死循环

循环条件如何设置?

 由于我们将right更新为mid,因此循环的条件应为left < right,若循环条件设置为left <= right,当left = right时,此时找到结果,而结果落在右边区间,此时会更新right的值,而right 更新为mid,即当前位置,从而死循环

分析完以上问题后,我们可以尝试编写查找右边区域最左边元素的代码:

//查找target第一次出现的位置(右边区间的左端点)
int left = 0,right = nums.length - 1,mid = left + (right - left)/2;
//循环条件应设置为left < right 
//不能设置为left <= right,否则会死循环
while(left < right){//当mid所指向的元素落在左边区间时,更新leftif(nums[mid] < target){left = mid + 1;}else{//当mid所指向的元素落在右边区间时,此时更新right//由于右边区间的元素大于等于target,即结果在该区间内,// 因此不能将right更新为mid - 1,而应更新为midright = mid;}//更新mid,当有两个中间元素时,mid应指向其中左边的元素mid = left + (right - left) / 2;
}

 此时我们查找target最后一次出现的位置

与查找第一次出现位置的思路相同,我们首先将数组分为两个部分:

其中,左边区间内元素小于等于target,右边区间元素大于target

此时,要找的结果即为左边区间的右端点

 同样的,定义left指向0位置,right指向最后一个元素,mid指向中间位置

若mid所指向的元素落在左边区间,此时需要更新left的值,由于要找的结果落在此区间内,即mid所指向的位置可能就是最终结果,因此不能将left更新为mid + 1,而应更新为mid

若mid所指向的元素落在右边区间,此时需要更新right的值,由于要找的结果不在右边区间,因此可将right的值更新为mid - 1

当left和right之间元素为偶数个时,此时中间元素有两个,应该选择哪一个作为中间元素?

 由于我们查找的是左边区间内最右边的元素,因此,应该选择右边的元素作为中间元素

mid = left + (right - left + 1) / 2;

同样的,当选择左边元素作为中间元素时,也会造成死循环

此时left的值一直更新为当前位置,造成死循环

循环条件的设置:

循环条件也同样应该设置为left < right,否则会死循环

此时我们尝试编写查找左边区间右端点代码:

//查找区间右端点
left = mid;
right = nums.length - 1;
mid = left + (right - left + 1)/2;
while(left < right){//当mid所指向的值落在右边区域时,更新右端点if(nums[mid] > target){right = mid - 1;}else{//当mid所指向的值落在左边区域时,更新左端点//由于左边区间的元素小于等于target,即结果在该区间内,//因此不能将left更新为mid + 1,而应更新为midleft = mid;}//更新mid的值,若有两个中间元素时,mid应指向其中右边的元素mid = left + (right - left + 1) / 2;
}

完整代码:

class Solution {public int[] searchRange(int[] nums, int target) {int[] ret = {-1,-1};//若数组为空,直接返回retif(nums.length == 0){return ret;}//查找target第一次出现的位置(右边区间的左端点)int left = 0,right = nums.length - 1,mid = left + (right - left) / 2;//循环条件应设置为left < right//不能设置为left <= right,否则会死循环while(left < right){//当mid所指向的元素落在左边区间时,更新leftif(nums[mid] < target){left = mid + 1;}else{//当mid所指向的元素落在右边区间时,此时更新right//由于右边区间的元素大于等于target,即结果在该区间内,// 因此不能将right更新为mid - 1,而应更新为midright = mid;}//更新mid,当有两个中间元素时,mid应指向其中左边的元素mid = left + (right - left) / 2;}//此时left = right = mid,使用哪一个变量进行判断和更新都可以//若数组中无值为target的元素,直接返回retif(nums[left] == target){ret[0] = left;}else{return ret;}//查找区间右端点left = mid;right = nums.length - 1;mid = left + (right - left + 1)/2;while(left < right) {//当mid所指向的值落在右边区域时,更新右端点if (nums[mid] > target) {right = mid - 1;} else {//当mid所指向的值落在左边区域时,更新左端点//由于左边区间的元素小于等于target,即结果在该区间内,//因此不能将left更新为mid + 1,而应更新为midleft = mid;}//更新mid的值,若有两个中间元素时,mid应指向其中右边的元素mid = left + (right - left + 1) / 2;}ret[1] = left;return ret;}
}

题目来自: 

34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)

相关文章:

在排序数组中查找元素的第一个和最后一个位置(Java详解)

一、题目描述 给你一个按照非递减顺序排列的整数数组 nums&#xff0c;和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值 target&#xff0c;返回 [-1, -1]。 你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。 示…...

k8s 安装firewalld导致的网络疑难问题处理

场景 ubuntu 操作系统,部署了k8s集群,n 台 机器,某些机器之间 telnet ip 10250不通。 ufw 是关闭的,然后抓包会看到如下错误 04:43:09.154362 IP 192.168.1.3.56608 > 192.168.1.183.8000: Flags [S], seq 3664350430, win 64240, options [mss 1460,sackOK,TS val 281…...

人工智能中的巨兽:图神经网络大模型的崛起

导言 图神经网络大模型的涌现标志着人工智能领域的一次革命。本文将深入研究这些庞大而强大的模型&#xff0c;探讨其背后的技术原理、关键应用以及引发的社会影响。 1. 技术原理 图神经网络大模型以其对图结构数据的卓越处理能力而著称。其技术原理包括&#xff1a; 图卷积神…...

【LeetCode刷题笔记(6-2)】【Python】【三数之和】【双指针】【中等】

文章目录 引言三数之和题目描述示例示例1示例2示例3 提示 解决方案3&#xff1a;【双指针】结束语 三数之和 引言 编写通过所有测试案例的代码并不简单&#xff0c;通常需要深思熟虑和理性分析。虽然这些代码能够通过所有的测试案例&#xff0c;但如果不了解代码背后的思考过程…...

02_Web开发基础之JavaScript

Web开发基础之JavaScript 学习目标和内容 1、能够描述Javascript的作用 2、能够使用分支结构if语句逻辑判断 3、能够使用其中一种循环语句 4、能够定义javaScript中的函数 5、能够定义javaScript中的对象 6、能够描述DOM的作用 7、能够通过DOM操作HTML标签元素及其属性 8、能够…...

如何控制Elasticsearch搜索的相关性?

控制相关性 纯粹处理结构化数据(例如日期、数字和 字符串枚举)很简单:他们只需要检查一个文档(或 行,在关系数据库中)与查询匹配。 虽然布尔值是/否匹配是全文搜索的重要组成部分,但它们 光靠自己是不够的。相反,我们还需要知道每个的相关性 document 是查询。全文搜索…...

基于urllib库的网页数据爬取

实验名称&#xff1a; 基于urllib库的网页数据爬取 实验目的及要求&#xff1a; 【实验目的】 通过本实验了解和掌握urllib库。 【实验要求】 1. 使用urllib库爬取百度搜索页面。 2. 使用urllib库获取百度搜索的关键字搜索结果&#xff08;关键字任选&#xff09;。 实验原理及…...

Python如何匹配库的版本

目录 1. 匹配库的版本 2. Python中pip&#xff0c;库&#xff0c;编译环境的问题回答总结 2.1 虚拟环境 2.2 pip&#xff0c;安装库&#xff0c;版本 1. 匹配库的版本 &#xff08;别的库的版本冲突同理&#xff09; 在搭建pyansys环境的时候&#xff0c;安装grpcio-tools…...

日志审计在网络安全中的重要性

日志审计是一种通过分析、识别和验证各种日志信息&#xff0c;以帮助企业了解其网络和系统的安全状态和活动的过程。这些日志信息可能来自各种来源&#xff0c;包括服务器、网络设备、应用程序、操作系统等。 日志审计的主要功能包括&#xff1a; 1.识别潜在的安全威胁&#…...

浅谈基于不信任的防御性编程

背景 在实际开发过程中&#xff0c;我们经常遇到这样的场景&#xff1a; 后端报错了&#xff0c;手忙脚乱一顿排查&#xff0c;发现是前端传的参数为空&#xff0c;或者格式不对&#xff1b;后端又报错了&#xff0c;传参没问题&#xff0c;根据日志流发现&#xff0c;是某“给…...

线性代数(一)

1.标量&#xff1a;标量由只有⼀个元素的张量表⽰。 x np.array(3.0) y np.array(2.0) x y, x * y, x / y, x ** y (array(5.), array(6.), array(1.5), array(9.))2.向量&#xff1a;向量可以被视为标量值组成的列表&#xff0c;列向量是向量的默认⽅向。 x np.arange(4…...

k8s-learning-why we need pod

应用场景 应用从虚拟机迁移到容器中 为什么虚拟机中的应用不能无缝迁移到容器中 虚拟机中应用&#xff1a;一组进程&#xff0c;被管理在systemd或者supervisord中 容器的本质&#xff1a;一个容器一个进程 所以将运行在虚拟机中的应用无缝迁移到容器中&#xff0c;与容器…...

【CASS精品教程】cass11提示“请不要在虚拟机中运行此程序”的解决办法

文章目录 一、问题提示二、解决办法一、问题提示 按照正常安装教程安装好南方测绘cass 11之后,打开的时候可能会有以下提示:请不要在虚拟机中运行此程序,如下图所示: 遇到问题,咱们就想办法解决问题,下面将自己尝试的方法及最终解决情况跟大家说一下,供参考。 二、解决…...

【算法Hot100系列】正则表达式匹配

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

html 基础学习笔记

Date:20231212 html标签 基础学习笔记 一、web和internet 1.1、Internet简介 Internet 是一个全球性的计算机互联网络&#xff0c;中文名称有"因特网"、“国际互联网”、“网际网”、"交互网络"等Internet提供的主要服务 Telnet、Email、www、BBS、FTP等…...

7-4 天梯赛的善良

天梯赛是个善良的比赛。善良的命题组希望将题目难度控制在一个范围内&#xff0c;使得每个参赛的学生都有能做出来的题目&#xff0c;并且最厉害的学生也要非常努力才有可能得到高分。 于是命题组首先将编程能力划分成了 106 个等级&#xff08;太疯狂了&#xff0c;这是假的&…...

案例精选|聚铭综合日志分析系统助力长房集团“智慧房产”信息化建设

长沙房产&#xff08;集团&#xff09;有限公司&#xff08;简称“长房集团”&#xff09;始创于2004年3月&#xff0c;是一家由长沙市人民政府授权组建的国有独资企业。截至2021年底&#xff0c;企业总资产逾452亿元&#xff0c;总开发面积1300多万平方米&#xff0c;已开发项…...

HarmonyOS给应用添加消息通知

给您的应用添加通知 通知介绍 通知旨在让用户以合适的方式及时获得有用的新消息&#xff0c;帮助用户高效地处理任务。应用可以通过通知接口发送通知消息&#xff0c;用户可以通过通知栏查看通知内容&#xff0c;也可以点击通知来打开应用&#xff0c;通知主要有以下使用场景…...

【C语言】cache和程序访问的局部性对程序性能的影响

文章目录 1&#xff0e;源程序比较其性能影响2&#xff0e;内存分配&#xff08;1&#xff09;静态存储区&#xff08;static&#xff09;&#xff1a;&#xff08;2&#xff09;栈区&#xff08;stack&#xff09;&#xff1a;&#xff08;3&#xff09;堆区&#xff08;heap&…...

数字棱形(课程F)

输入1个整数N&#xff0c;输出N行的如下形状的数字棱形。 例如&#xff1a;N4时&#xff1a; ___1 __222 _33333 4444444 _33333 __222 ___1 (注&#xff1a;上面使用下划线’_’表示空格&#xff0c;以避免看不清造成误解) 输入格式 第一行1个正整数&#xff1a;N&#xff0…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...