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

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

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

题目

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

在这里插入图片描述

解法一

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相等的就是开始位置doleft++;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};elsereturn {-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的原因也是如此。


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

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

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

相关文章

突破技术边界:R与jsonlite库探秘www.snapchat.com的数据之旅

概述 Snapchat是一款流行的社交媒体应用&#xff0c;它允许用户发送和接收带有滤镜和贴纸的照片和视频&#xff0c;以及创建和观看故事和发现内容。Snapchat的数据是非常有价值的&#xff0c;因为它可以反映用户的行为、偏好和趋势。然而&#xff0c;Snapchat的数据并不容易获…

整除判断-判断正整数a能否被b整除,如果不能整除,输出商和余数 C语言xdoj42

问题描述 判断正整数a能否被b整除&#xff0c;如果不能整除&#xff0c;输出商和余数 输入说明 输入两个正整数a和b&#xff08;0<a, b<10000&#xff09;&#xff0c;a和b之间用空格分隔。 输出说明 如果a能被b整除&#xff0c;输出yes&#xff0c;否则在同…

Unity 使用 Plastic 同步后,正常工程出现错误

class Newtonsoft.Json.Linq.JToken e CS0433:类型"JToken"同时存在于"Newtonsoft.Json.Net20,Version3.5.0.0,Cultureneutral,,PublicKeyToken30ad4fe6b2a6aeed"和"Newtonsoft.Json, Version12.0.0.0,Cultureneutral,PublicKeyToken30ad4fe6b2a6aeed…

在Android设备上设置和使用隧道代理HTTP

随着互联网的深入发展&#xff0c;网络信息的传递已经成为人们日常生活中不可或缺的一部分。对于我们中国人来说&#xff0c;由于某些特殊的原因&#xff0c;访问国外网站时常常会遇到限制。为了解决这个问题&#xff0c;使用代理服务器成为了许多人的选择。而在Android设备上设…

「解析」Windows 如何优雅使用 Terminal

所谓工欲善其事必先利其器&#xff0c;对于开发人员 Linux可能是首选&#xff0c;但是在家学习的时候&#xff0c;我还是更喜欢使用 Windows系统&#xff0c;首先是稳定&#xff0c;其次是习惯了。当然了&#xff0c;我还有一台专门安装 Linux系统的小主机用于学习Linux使用&am…

Gin 项目引入热加载

Gin 项目引入热加载 文章目录 Gin 项目引入热加载一、什么是热加载二、Air2.1 介绍2.2 特性特性&#xff1a;2.3 相关文档2.4 安装推荐使用 install.sh使用 go install 2.5 配置环境变量2.6 使用 三、Fresh3.1 介绍3.2 相关文档3.3 安装与使用 四、bee4.1 介绍4.2 相关文档4.3 …

UE4 4.21使用编辑器蓝图EditorBlueprint方法

在UE4 4.21中&#xff0c;编辑器蓝图&#xff08;Editor Blueprint&#xff09;是一个强大的工具&#xff0c;允许开发者扩展和自定义Unreal编辑器的功能。通过编辑器蓝图&#xff0c;我们可以创建自定义的工具和功能&#xff0c;以优化开发流程。 本教程将指导您如何在UE4 4.…

SpringCloud之Eureka组件工作原理详解

Eureka是一种服务注册与发现组件&#xff0c;最初由Netflix开发并开源出来。它主要用于构建分布式系统中的微服务架构&#xff0c;并提供了服务注册、服务发现、负载均衡等功能。在本文中&#xff0c;我们将详细解释Eureka的工作原理。 一、Eureka概述 Eureka是Netflix开源的一…

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

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

【C语言进阶篇】关于指针的八个经典笔试题(图文详解)

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《C语言初阶篇》 《C语言进阶篇》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 &#x1f4cb; 前言&#x1f4ac; 指针笔试题&#x1f4ad; 笔试题 1&#xff1a;✅ 代码解析⁉️ 检验结果&…

Redis (三)

1、redis复制 简单的概括就是主从复制&#xff0c;master以写为主&#xff0c;Slave以读为主&#xff0c;当master数据发生变化的时候&#xff0c;自动将更新的数据异步同步到其他的slave是数据库。 使用这种机制的话&#xff0c;可以做到读写分离&#xff0c;可以减轻主机负担…

【React系列】React生命周期、setState深入理解、 shouldComponentUpdate和PureComponent性能优化、脚手架

本文来自#React系列教程&#xff1a;https://mp.weixin.qq.com/mp/appmsgalbum?__bizMzg5MDAzNzkwNA&actiongetalbum&album_id1566025152667107329) 一. 生命周期 1.1. 认识生命周期 很多的事物都有从创建到销毁的整个过程&#xff0c;这个过程称之为是生命周期&…