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

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

1.朴素二分查找

.二分查找

二分查找思路:
1.left=0,right=nums.size()-1(最后一个元素下标),取中间元素下标 mid=left+(right-left)/2 (防溢出)

2.nums[mid]>target ,说明mid右边的元素都大于target,就不用再从mid右边查找。right=mid-1

3.nums[mid]<target ,说明mid左边的元素都小于target,就不用再从mid左边查找。

left=mid+1

4.nums[mid]==tartget,找到目标值返回。

5.循环条件 left<=right,当left==right时,意味着只剩最后一个元素,有可能是目标值。

不断循环直到找到目标结果,或者left>right不满足循环条件。

class Solution {
public:int search(vector<int>& nums, int target) {int re=-1,left=0,right=nums.size()-1;while(left<=right){int i=left+(right-left)/2;if(nums[i]>target) right=i-1;else if(nums[i]<target) left=i+1;elsereturn i;}return re;}
};

2.查找区间左端点/右端点

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

这道题如果用朴素二分查找,虽然可以找到target==8的元素,但不一定就是目标值。

找到目标值再向左 向又查找不行吗?可以,但效率会降低。我们有其它方法可以更好的解决。

1.查找区间左端点

该方法对于朴素二分法不同的是,朴素二分法把区间分为3份,>target ==target <target。

查找区间左端点把区间分为2份,<target >=target(默认非递减)。

eg1.[5 7 7]  [8 8 10] 而目标值就在右区间的最左边。

1.如果mid落在左区间,mid指向的元素肯定不是目标值,可以让left=mid+1

2.如果mid落在右区间,mid指向的元素有可能是目标值,所以让right=mid 如果-1可能会跳过目标值。

所以right只会在右区间移动,而left最远只会到右区间的最左边。所以当left==right就可以求出结果。

3.循环条件为left<right,不能是left<=right,如果等于会一直循环,left==right

mid=(left+right)/2 mid值不变,还是在右区间,right=mid right值也不变。

4.mid的取值,mid=left+(right-left) 还是向上取整 mid=left+(right-left+1)?有什么区别?

如果只剩两个数[5 7 7]  [8 8 10] 的7 8。left指向7 right指向8,mid=left+(right-left+1) mid=1

此时mid指向8,落在右区间,right=mid。再取mid还是指向8,就会无限循环。

所以mid=left+(right-left) mid=0取靠左边的值,指向7,落在左区间,left=mid+1。此时left==right循环结束。

下面举2种极端情况

1.数组值全>target 只有右区间,right不断移动 left==0不动.left==right指向下标0

2.数组值全<arget 只有左区间,left不断移动 right==nums.szie()-1不动.left==right指向最后一个元素(因为mid=left+(right-left) mid=0取靠左边的值 不会出现mid==right left=mid+1越界的情况

 2.查找区间右端点

和查找左端点本质一样,但细节不同。

查找区间右端点把区间分为2份,<=target >target(默认非递减)。

eg1.[5 7 7 8 8] [ 10 ] 而目标值就在左区间的最右边。

1.如果mid落在右区间,mid指向的元素肯定不是目标值,可以让right=mid-1 

2.如果mid落在左区间,mid指向的元素可能是目标值,所以让left=mid 

所以left只会在左区间移动,而right最远只会到左区间的最右边。所以当left==right就可以求出结果。

3.循环条件为left<right,不能是left<=right,如果等于会一直循环,left==right

mid=(left+right)/2 mid值不变,还是在左区间,left=mid left值也不变。

4.mid的取值,mid=left+(right-left) 还是向上取整 mid=left+(right-left+1)?有什么区别?

如果只剩两个数[5 7 7 8 8 ][10] 的8 10。left指向8 right指向10,mid=left+(right-left) mid=0取靠左边的值 此时mid指向8,落在左区间,left=mid。再取mid还是指向8,就会无限循环。

所以mid=left+(right-left+1) mid=1取靠右边的值,指向10,落在右区间,right=mid-1。此时left==right循环结束。

class Solution {
public:vector<int> searchRange(vector<int>& nums, int target) {int le=-1,ri=-1;int left=0,right=nums.size()-1,mid=0;//处理边界情况if(nums.empty()) return {-1,-1};//取左端点下标while(left<right){mid=left+(right-left)/2;//取靠左边的值if(nums[mid]<target)left=mid+1;elseright=mid;}le=left;left=0,right=nums.size()-1;//取右端点下标while(left<right){mid=left+(right-left+1)/2;//取靠右边的值if(nums[mid]<=target)left=mid;elseright=mid-1;}ri=left;if(nums[left]==target) return {le,ri};else return {-1,-1}; //没找到的情况}
};

1.如果目标值是左端点,就把它套在右区间[5 7 7]  [8 8 10],让左边的+1来找,mid就要取靠左的值

2.如果目标值是右端点,就把它套在左区间[5 7 7 8 8 ][10],让右边的-1来找,mid就要取靠右的值


http://www.mrgr.cn/news/56261.html

相关文章:

  • SpringBoot使用RestTemplate实现发送HTTP请求
  • DirectX11:Position Based Fluid
  • Docker配置网站环境
  • 2019年计算机网络408真题解析
  • 怎么压缩word文档?给你推荐几个压缩word文档的方法
  • pymobiledevice3使用介绍(安装、常用命令、访问iOS沙盒目录)
  • 超详细JDK安装+环境配置教程
  • vnc+wsl2试用
  • 深入浅出剖析重量级文生图模型Flux.1
  • 数据结构图的应用最小生成树-普里姆算法(C语言代码+无向网+有向网+邻接矩阵存储结构)-最低附带图片+终端输入内容方便理解
  • 【Python爬虫系列】_031.Scrapy_模拟登陆中间件
  • 让你的 IDEA 使用更流畅 | IDEA内存修改
  • 常见的加密算法的分类及其原理
  • 利用自定义 ref 实现函数防抖
  • 批量合并同名Labelme标注文件内容
  • freeRTOS中互斥锁与信号量使用?
  • vue3学习记录-v-model
  • Numpy基础02
  • 浏览器控制的无线开关
  • 【03】RabbitMQ核心功能扩展
  • LeetCode718:最长重复子数组
  • [DB] NSM
  • 在线教育(培训+考试)/企业培训-企业培训平台-企业培训平台系统-企业内部培训系统-在线教育-Java语言开发
  • 「AIGC」n8n AI Agent开源的工作流自动化工具
  • php基础:数据类型、常量、字符串
  • 【内信互联】私有化安全性企业远程运维办公解决方案