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

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

  • 题目
  • 解法一
  • 解法二(二分查找)
    • 代码展示
    • 原理剖析

题目

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

在这里插入图片描述

解法一

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        int size = nums.size();
        
        //先考虑边界条件
        if(size == 0) return {-1, -1};
        if(nums[0] > target || nums[size-1] < target) return {-1, -1};

        int left = -1, right = size;
         //直接从左端开始遍历,找到第一个和target相等的就是开始位置
        do
            left++;
        while(nums[left] != target && left < size-1); // left < size-1 可以防止越界

        //直接从右端开始遍历,找到第一个和target相等的就是结束位置
        do  
            right--;
        while(nums[right] != target && right >= 1);   
        
            
        // 可能出现left和right遍历一遍都没有找到目标位置的情况,所以需要判断,此时用nums[left]还是nums[right]都可以
        if(nums[left] == target)
            return {left, right};
        else
            return {-1, -1};
    }
};

解法二(二分查找)

代码展示

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        int size = nums.size();
        //处理边界问题
        if(size == 0) return {-1, -1};
        int begin=-1, end=-1;
        // 找二分左端点
        int left = 0, right = size-1;
        while(left < right)
        {
            int mid = left+(right-left)/2;
            if(nums[mid] < target) left = mid+1;
            else right = mid; 
        }
        if(nums[left] == target) begin = left;
        else return {-1, -1};

        //找二分右端点
        left = 0, right = size-1;
        while(left < right)
        {
            int mid = left+(right-left+1)/2;
            if(nums[mid] <= target) left = mid;
            else right = mid-1; 
        }
        if(nums[right] == target) end = right;
        else return {-1, -1};


        return {begin, end};
    }
};

原理剖析

   二分查找需要通过得出这道题目所包含的二段性,来一步一步缩小范围,找到目标值,这道题一个关键的条件就是数组是非递减的,也就意味着数组是递增或者是相等的。二段性怎么找到呢?

   若要找到target,取中心位置为mid,那么就会立刻排出掉一半无关的值,然后再令left=mid,即可缩小排查范围。这样就可以发现这道题使用二分查找来解题的二段性。
在这里插入图片描述


首先确定循环结束条件
有两种选择:

  1. while(left < right)
  2. while(left <= right)

区别就在于是否需要当left == right时再进行判断。

  1. 当left == right时, 已经找到了左端点或是右端点,此时不需要冗余的在进行。
  2. 第二点原因之后解释。
    所以选择第一点更为合理。

利用二分找到左端点

  1. nums[mid] < target时, 左端点在右半部分,所以left = mid+1;
  2. nums[mid] > target时, 左端点在左半部分,所以right = mid-1
  3. nums[mid] == target时,此时左端点就在left和right之间,此时不能移动left, 因为也许左端点就在mid的左边,也不能将right移动到mid的左边,因为这两种操作都会使得左端点在二分缩小里面被错过。所以可以移动right, 此时right = mid;
  4. 可以将2,3合并,得到若nums[mid] >= targetright = mid;

利用二分找到右端点

  1. nums[mid] < target时, 右端点在右半部分,所以left = mid+1;
  2. nums[mid] > target时, 右端点在左半部分,所以right = mid-1
  3. nums[mid] == target时,此时右端点就在left和right之间,此时不能移动right, 因为也许右端点就在mid的左边,也不能将right移动到mid的左边,因为这两种操作都会使得左端点在二分缩小里面被错过。所以可以移动right, 此时left = mid;
  4. 可以将1,3合并,得到若nums[mid] <= targetleft = mid;

while(left <= right)导致的死循环问题
   因为当left==right时, 无论是找左端点还是右端点,left 和 right依旧指向mid,永远不会改变,因此如果while(left <= right)的话,就会导致死循环。

mid的取值问题
   通过代码可以看到,mid的取值有两种,分别是:

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

   由于是二分,都是除二,所以上面1代表的意思就是二分后向下取整,2代表的意思就是向上取整。
   下面来看找二分右端点的特殊情况;
在这里插入图片描述
   若现在left和right的指向如上图所示,若是mid取值:mid = left+(right-left)/2;,则mid位于1处, 若target就是1, 此时执行的是if(nums[mid] <= target) left = mid;,就会导致left一直指向1,right一直指向不变,没有left<right,while循环就不会结束,就会造成死循环。所以得向上取整,此时mid位于2处, 就不会触发死循环。找左端点使用mid = left+(right-left)/2的原因也是如此。


    😄 创作不易,你的点赞和关注都是对我莫大的鼓励,再次感谢您的观看😄

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

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

相关文章

CentOs搭建Kafka集群

Centos7搭建Kafka集群 一、集群规划二、环境准备三、安装kafka集群1、下载kafka安装包2、解压3、配置环境变量4、编辑配置文件①修改broker.id②配置kafka运行日志路径③配置Zookeeper集群地址 5、启动集群6、测试kafka①、创建topic②、查看当前服务器中的所有topic③、生产者…

Springcloud 微服务实战笔记 Zuul

优点 解决路由规则与服务实例维护问题。对于类似签名校验、登录校验在微服务架构中的冗余问题。 入门使用 构建网关 pom.xml引入 spring-cloud-starter-netflix-zuul <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-c…

苹果Vision Pro将于1月27日上市!

在无数期待中&#xff0c;苹果全新产品Vision Pro头显终于定下上市日期。 彭博社记者马克古曼&#xff08;Mark Gurman&#xff09;于近日在X&#xff08;前推特&#xff09;平台爆料了这一信息&#xff0c;预计苹果Vision Pro头显将于2024年1月27日率先在美国上市。 在过去看…

LeetCode 641. 设计循环双端队列

难度&#xff1a;Medium 641. 设计循环双端队列 设计实现双端队列。 实现 MyCircularDeque 类: MyCircularDeque(int k) &#xff1a;构造函数,双端队列最大为 k 。boolean insertFront()&#xff1a;将一个元素添加到双端队列头部。 如果操作成功返回 true &#xff0c;否…

Java CPU或内存使用率过高问题定位教程

简介 Spring cloud微服务广泛应用后&#xff0c;服务的监控和运维压力也与日俱增&#xff0c;经常有服务出现CPU或者内存使用率过高的告警&#xff0c;那么遇到这样的问题我们该如何排查呢&#xff1f;我们可以借助哪些工具来定位问题呢&#xff1f;本文将介绍一下遇到此类问题…

案例精选|淄博绿能燃气工程有限公司日志审计系统建设方案

淄博绿能燃气工程有限公司&#xff0c;成立于1994年&#xff0c;前身为淄博市煤气公司管道液化气分公司。公司业务主要涉及天然气、液化气等市政工程施工及城镇燃气供应等领域&#xff0c;具有市政公用工程施工总承包二级资质&#xff0c;《压力管道安装许可证》压力管道安装GB…

亚信安慧AntDB数据库:数字化时代的数据库创新引领者

AntDB数据库以其卓越的创新能力&#xff0c;集中体现在融合统一与实时处理两大关键领域。作为一款服务全国超过10亿用户的分布式数据库&#xff0c;其独特之处在于长期积累的经验、多样性的支持能力、快速响应的数据处理速度以及卓越的系统稳定性。AntDB不仅仅是一个数据库系统…

Node.js+Express+Mysql实现分页查询

接收请求代码 router.get(/api/user/page, async (req, res) > {let pageNo req.query.pageNo;let pageSize req.query.pageSize;const startIndex (pageNo - 1) * pageSize;const queryString SELECT * FROM sys_user LIMIT ${startIndex}, ${pageSize};data await …

【React系列】父子组件通信—props属性传值

本文来自#React系列教程&#xff1a;https://mp.weixin.qq.com/mp/appmsgalbum?__bizMzg5MDAzNzkwNA&actiongetalbum&album_id1566025152667107329) 一. 认识组件的嵌套 组件之间存在嵌套关系&#xff1a; 在之前的案例中&#xff0c;我们只是创建了一个组件App&…

Netty实战(待完善)

Netty组件 1. Bootstrap, ServerBootstrap Netty 中 Bootstrap 类是客户端程序的启动引导类&#xff0c;ServerBootstrap 是服务端启动引导类。 2. NioEventLoop, NioEventLoopGroup NioEventLoop 中维护了一个线程和任务队列&#xff0c;支持异步提交执行任务&#xff0c;…

小梅哥Xilinx FPGA学习笔记20——无源蜂鸣器驱动设计与验证(音乐发生器设计)

目录 一&#xff1a;章节导读 二&#xff1a;无源蜂鸣器驱动原理 三&#xff1a;PWM 发生器模块设计 3.1 PWM 发生器模块框图 3.2 PWM 发生器模块接口功能描述 3.3 PWM波生成设计文件代码 3.4 测试仿真文件 3.5 测试仿真结果 3.6 板级调试与验证之顶层文件设计 四&am…

neo4j图数据库安装和测试

neo4j图数据库安装和测试 1. 下载合适的neo4j软件版本。 https://we-yun.com/doc/neo4j/ https://neo4j.com/deployment-center/#enterprise 2. 下载JAVAJDK 由于neo4j是一个用Java编写的图形数据库&#xff0c;因此在安装和运行Neo4j之前&#xff0c;需要先安装Java Developm…

【shell漫步】1 变量定义和使用

碎碎念 转眼间已经使用了一个月的shell了&#xff0c;作为一个纯小白&#xff0c;我特别理解刚入门的时候对于linux和shell一头雾水的状态&#xff0c;尤其是打算开始学&#xff0c;但是又找不到学习的“入口函数”的那种感受。所以打算整理一下shell的骨架。shell给我的感触就…

【C#】知识点实践序列之UrlEncode在线URL网址编码、解码

欢迎来到《小5讲堂》&#xff0c;大家好&#xff0c;我是全栈小5。 这是2024年第8篇文章&#xff0c;此篇文章是C#知识点实践序列文章&#xff0c; 博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 地址编码大家应该比较经常遇到和使用到&…

记一次使用mpvue开发微信小程序动画播放播放完成再播放下一个动画,实现动画队列的实战操作

微信小程序wxss支持Css的keyframes动画&#xff0c;我们想通过事件监听&#xff0c;在动画开始、动画播放阶段、动画播放结束的时候进行下一步动作。如下图&#xff0c;有一个从右飘入&#xff0c;然后从左侧出去的动画&#xff0c;我们希望的是&#xff0c;前一个出去后&#…

微众区块链观察节点的架构和原理 | 科普时间

践行区块链公共精神&#xff0c;实现更好的公众开放与监督&#xff01;2023年12月&#xff0c;微众区块链观察节点正式面向公众开放接入功能。从开放日起&#xff0c;陆续有多个观察节点在各地运行&#xff0c;同步区块链数据&#xff0c;运行区块链浏览器观察检视数据&#xf…

STM32 内部 EEPROM 读写

STM32 的某些系列 MCU 自带 EEPROM。笔者使用的 STM32L151RET6 自带 16 KB 的 EEPROM&#xff0c;可以用来存储自定义的数据。在芯片选型时&#xff0c;自带 EEPROM 也可以作为一个考量点&#xff0c;省去了在外接 EEPROM 的烦恼。 下面简单介绍下 STM32 内部 EEPROM 的读写流…

区块链技术与应用 【全国职业院校技能大赛国赛题目解析】第一套区块链系统部署与运维

第一套区块链系统部署与运维题目 环境 : ubuntu20 fisco : 2.8.0 子任务1-2-1: 搭建区块链系统并验证 题意: 要求搭建一条四节点的区块链系统,我们选择使用fisco作为此次测试的链子 我们使用build_chain.sh进行构建单机四节点,并且使用官方的默认端口【正式比赛大概率不…

Python 操作 JMeter 探索:pymeter 实操指南

概要 JMeter 是一个流行的性能测试工具&#xff0c;用于测试 Web 应用程序的性能和负载。它通常与 GUI 一起使用&#xff0c;但如果您想在自动化测试中集成 JMeter&#xff0c;或者以编程方式创建和运行测试计划&#xff0c;那么 pymeter 库将是一个强大的工具。本文将介绍如何…

快速、准确地检测和分类病毒序列分析工具 ViralCC的介绍和详细使用方法, 附带应用脚本

介绍 viralcc是一个基因组病毒分析工具&#xff0c;可以用于快速、准确地检测和分类病毒序列。 github&#xff1a;dyxstat/ViralCC: ViralCC: leveraging metagenomic proximity-ligation to retrieve complete viral genomes (github.com) Instruction of reproducing resul…