二分查找(非朴素)--在排序数组中查找元素的第一个和最后一个位置

 个人主页:Lei宝啊 

愿所有美好如期而遇


目录

本题链接 

输入描述

输出描述

算法分析

1.算法一:暴力求解

2.算法二:朴素二分算法

3.算法三:二分查找左右端点

3.1查找左端点

3.1.1细节一:循环条件

3.1.2细节二:mid的值

3.2查找右端点

解题源码 


本题链接 

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

输入描述

我们选择示例1,接口为vector<int> searchRange(vector<int>& nums, int target) ,向nums中写入非递减的数字,也就是说可以有多个重复的相同数字。

输出描述

由于nums中可能有多个值与target相等,所以我们需要记录这个区间的左端点和右端点,然后返回这个区间,如果找不到,则区间为[-1,-1]。

算法分析

1.算法一:暴力求解

直接从左到右扫描这个数组,通过begin和end变量来记录相等于target的起始位置和结束位置,找不到则返回[-1,-1],时间复杂度为O(N)。

2.算法二:朴素二分算法

直接二分,如果寻找的target在nums中只有一个,那么时间复杂度为log(N),但是如果有多个的话,我们还是需要去遍历mid的左边和mid的右边,如果整个数组所有值都与target相等,就相当于要遍历整个数组,时间复杂度仍然为O(N),这里我们使用朴素二分算法仍然不是最优的。

3.算法三:二分查找左右端点
3.1查找左端点

我们可以将数组分成两个区间,以[5,7,7,8,8,10],target = 8为例,既然我们要找左端点,也就是最左边的那个8,所以我们将数组分成小于target的区间大于等于target的区间,即[5,7,7]   [8,8,10]这两个区间。(lhs意为left side hand即左手边,rhs意为right side hand即右手边)

我们定义一个mid,mid = lhs + (rhs - lhs) / 2,并且有两种结果:

  • 当nums[mid] < target ,lhs = mid + 1;
  • 当nums[mid] >= target, rhs = mid;

你可能会问,为什么rhs = mid, 按照我们朴素二分算法的理解,应该是rhs = mid - 1, 我们可以举个例子,如果说mid = 3,也就是上面最左边的8,那么再怎么样我们也无法找到左端点了。

同时按照我们上面的两种结果,我们也可以发现一个事实,就是rhs永远不会出他的区间,lhs是可以跨区间的,当lhs == rhs时,也就代表着循环结束了。

所以这就是全部了吗?当然不是,他还有其他细节,这些细节一但注意不到,就是一个接一个的死循环。

3.1.1细节一:循环条件

朴素二分算法循环条件是lhs <= rhs,那么我们这里也是这样吗?上面我们提过一个事实,就是说当lhs == rhs时就已经结束了,而且正好是我们的左端点,所以说我们不用再去判断相等的情况,你可能会说,碰巧罢了,你这是能找到结果,你要是找不到呢?如果nums里全部大于target呢?如果nums里全部小于target呢?那我们分三种情况:

所以我们不需要判断lhs == rhs这种情况,因为我们上述三种情况就是本题的所有情况,而我们也证实了当lhs == rhs时就是我们的结果,要么找到,要么就找不到。

但是有人会犯倔,我嫌麻烦,还得想这么多东西,不就多判断一次嘛?我就用lhs <= rhs, 有问题吗?还是分三种情况,运气好点就不死循环。

所以我们循环条件也有两个细节:

  • 细节一:无需判断lhs == rhs,因为此时已经是结果了。
  • 细节二: 如果真的比较了,可能会死循环,在leetcode众多测试用例中,一定是错的。
3.1.2细节二:mid的值

我们上面直接让mid = lhs + (rhs - lhs) / 2; 可能你也没有思考为什么,可不可以,事实上,在查找左端点时这样正好可以,但是放在查找右端点上就是死循环,那么右端点mid怎么算?

mid = lhs + (rhs - lhs + 1) / 2;那么我们把这个用在左端点上看看效果。

我们可以发现:

  • 选择第一种方式,mid的值偏向于左边下标
  • 选择第二种方式,mid的值偏向于右边下标 

细节很多,不注意就死循环,但是我们不要死记硬背,要去理解,怎么样就死循环了,这才是我们该做的。

3.2查找右端点

查找右端点和查找左端点思路完全相同,只是有些细节不同,我们这里指出:

  1. 区间的划分:大于target的区间的小于等于target的区间
  2. mid的计算:mid = lhs + (rhs - lhs + 1) / 2;

剩下的就是一个模子了。 

解题源码 

class Solution {
public:vector<int> searchRange(vector<int>& nums, int target) {vector<int> v(2,-1);if(nums.size() <= 0)  return v;//计算左端点int lhs = 0, rhs = nums.size() - 1, mid = lhs + (rhs - lhs) / 2;while(lhs < rhs){//分区间if(nums[mid] < target) lhs = mid + 1;   //小于区间else  rhs = mid;                        //大于等于区间        mid = lhs + (rhs - lhs) / 2;}if(nums[rhs] == target) v[0] = rhs;//计算右端点lhs = 0, rhs = nums.size() - 1, mid = lhs + (rhs - lhs + 1) / 2;while(lhs < rhs){//分区间if(nums[mid] > target) rhs = mid - 1;   //大于区间else  lhs = mid;                        //小于等于区间        mid = lhs + (rhs - lhs + 1) / 2;}if(nums[rhs] == target) v[1] = rhs;return v;}
};

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

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

相关文章

pycharm找回误删的文件和目录

昨天不知道做了什么鬼操作&#xff0c;可能是运行了几个git命令&#xff0c;将项目里面的几个文件删除了&#xff0c;有点懵。 我知道pycharm可以找回文件的历史修改记录&#xff0c;但是对于删除的文件能否恢复&#xff0c;一直没试过。 找到删除文件的目录&#xff0c;点击右…

解决RestHighLevelClient报错missing authentication credentials for REST request

使用ElasticSearch Java API时遇到错误 "missing authentication credentials for REST request" 这是代码: RestHighLevelClient esClient new RestHighLevelClient(RestClient.builder(new HttpHost("localhost",9200,"http")));CreateIndexR…

utf8mb4_0900_ai_ci、utf8mb4_0900_as_ci、utf8mb4_0900_as_cs 这三者有什么区别

utf8mb4_0900_ai_ci, utf8mb4_0900_as_ci, 和 utf8mb4_0900_as_cs 是 MySQL 数据库中使用的字符集和校对规则。这些校对规则决定了如何比较和排序字符数据。它们属于 utf8mb4 字符集&#xff0c;这是 UTF-8 编码的超集&#xff0c;支持最多 4 个字节的字符&#xff0c;能够存储…

【开源】基于JAVA语言的创意工坊双创管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 管理员端2.2 Web 端2.3 移动端 三、系统展示四、核心代码4.1 查询项目4.2 移动端新增团队4.3 查询讲座4.4 讲座收藏4.5 小程序登录 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的创意工坊双创管理…

SpringBoot 增量/瘦身部署jar 包

背景 SpringBoot 项目的部署一般采用全量jar 包方式部署相关项目&#xff0c;如果我们对相关的Contrller\Service\Dao\Mapper 层进行相关业务调整就需要重新编译全量jar 包&#xff08;包大小约为200M左右&#xff09;实在太麻烦了。 本文:重点讲解使用SpringBoot 的增量/瘦身…

小型企业网设计-课设实验-爆款实验

可以按照我的配置依次配置&#xff0c;成品打包文件&#xff0c;请&#xff1a;Ensp888 <Huawei>sys Enter system view, return user view with CtrlZ. [Huawei]un in en Info: Information center is disabled. [Huawei]# [Huawei]sysname SW5 [SW5]# [SW5]vlan batch…

2007-2022年上市公司华证ESG工具变量数据(原始数据+处理代码+结果)

2007-2022年上市公司华证ESG工具变量数据&#xff08;原始数据处理代码结果&#xff09; 1、时间&#xff1a;2007-2022年 2、范围&#xff1a;上市公司 3、指标&#xff1a;证券代码、id、证券简称、year、华证_ESG综合评级、华证_ESG赋值 、华证_ESG综合得分、华证_E评级、…

Mysql 容易忘的 sql 指令总结

目录 一、操作数据库的基本指令 二、查询语句的指令 1、基本查询语句 2、模糊查询 3、分支查询 4、 分组查询 5、分组查询 6、基本查询总结&#xff1a; 7、子查询 8、连接查询 三、MySQL中的常用函数 1、时间函数 2、字符串函数 3、聚合函数 4、运算函数 四、表…

基于FPGA的数字电路(PWM脉宽调制)

一.PWM的制作原理 假如我们有一个锯齿波&#xff0c;然后在锯齿波上设置一个阈值&#xff08;黑色水平虚线&#xff09;&#xff0c;凡是大于该阈值时输出均为高电平&#xff0c;反之则为低电平&#xff0c;这样我们是不是就得到一个PWM信号呢&#xff1f;如果我们想调整它的占…

【Spring】spring的容器创建

目录 控制反转IOC 依赖注入DI 创建spring的容器方式&#xff1a; 思考&#xff1a; spring整合Junit4 控制反转IOC 把对象的创建和对象之间的调用过程&#xff0c;交给Spring管理&#xff0c;IOC是容器&#xff0c;是思想。&#xff01;&#xff01;&#xff01; 依赖注入…

算法导论复习(十三)最大流

前面一个写从哪里来的&#xff0c;第二个是还可以加多少流量&#xff0c;检查完的画下划线 找到一条增广链以后就对这条链上的数据进行处理 看看反向如何处理 还可以进行第三次检查 最后不能增加了就是最后的结果了

Java关键字(1)

Java中的关键字是指被编程语言保留用于特定用途的单词。这些关键字不能用作变量名或标识符。以下是Java中的一些关键字&#xff1a; public&#xff1a;表示公共的&#xff0c;可以被任何类访问。 private&#xff1a;表示私有的&#xff0c;只能被定义该关键字的类访问。 cl…

超详细YOLOv8姿态检测全程概述:环境、训练、验证与预测详解

目录 yolov8导航 YOLOv8&#xff08;附带各种任务详细说明链接&#xff09; 搭建环境说明 不同版本模型性能对比 不同版本对比 参数解释 模型解释 训练 训练示意代码 训练数据与.yaml配置方法 .yaml配置 数据集路径 标签数据说明 训练参数说明 训练过程示意及输出…

系列六、Consul

一、Consul 1.1、概述 Consul是一套开源的分布式服务发现和配置管理系统&#xff0c;由HashiCorp公司用Go语言开发。他提供了微服务系统中的服务治理、配置中心、控制总线等功能。这些功能中的每一个功能都可以单独使用&#xff0c;也可以一起使用以构建全方位的服务网格&…

【Web】vulhub-httpd apache解析漏洞复现(1)

目录 ①CVE-2017-15715 ②apache_parsing_vulnerability ①CVE-2017-15715 贴出源码&#xff1a; <?php if(isset($_FILES[file])) {$name basename($_POST[name]);$ext pathinfo($name,PATHINFO_EXTENSION);if(in_array($ext, [php, php3, php4, php5, phtml, pht]))…

Oracle VirtualBox中Linux系统基本使用方法——备赛笔记——2024全国职业院校技能大赛“大数据应用开发”赛项

前言 小北的这篇博客介绍的是关于用VirtualBox中下载好的ubuntu系统中&#xff0c;为搭建Hadoop平台所做的命令操作准备&#xff0c;希望能帮助不会的人有指引作用。 没有安装好VirtualBox中的ubuntu系统以及创建Hadoop账户的请参考小北之前的三篇博客&#xff1a; ubuntu18…

申请虚拟VISA卡Fomepay教程

fomepay 用下面的注册链接直达 https://gpt.fomepay.com/#/pages/login/index?dS21BA1 或者扫描下面图片的二维码直达注册 注册后尽量随用随充值不建议放大量现金在里面。

Java基础02-Java编程基础

文章目录 变量&#xff08;Variables&#xff09;局部变量和成员变量局部变量&#xff08;Local Variables&#xff09;成员变量&#xff08;Instance Variables&#xff09; 标识符&#xff08;Identifiers&#xff09;八种基本数据类型原始数据类型&#xff08;Primitive Dat…

uniapp中组件库的丰富NumberBox 步进器的用法

目录 基本使用 #步长设置 #限制输入范围 #限制只能输入整数 #禁用 #固定小数位数 #异步变更 #自定义颜色和大小 #自定义 slot API #Props #Events #Slots 基本使用 通过v-model绑定value初始值&#xff0c;此值是双向绑定的&#xff0c;无需在回调中将返回的数值重…

linux安装python

文章目录 前言一、下载安装包二、安装1.安装依赖2.解压3.安装4.软链接5.验证 总结 前言 本篇文章介绍linux环境下安装python。 一、下载安装包 下载地址&#xff1a;官方网站 我们以最新的标准版为例 二、安装 1.安装依赖 yum -y install openssl-devel ncurses-devel li…