二分查找算法

题目要求:
给定目标值 和指定数组, 数组为升序数组 ,在数组中查找到目标值 ,如果成功返回下标,失败则返回-1。(时间复杂度尽可能短)
题目解析以及核心思路:
题目解析:
在数组中寻找目标值,只需要遍历数组一次即可, 此时的时间复杂度为O(N)。
在这里我们介绍一种快捷的查找算法--二分算法。
这种查找算法时间复杂度可以缩减到O(logN)。
算法思想: 对于某一组数组,根据题目要求的特殊规律 ,选取某点, 把数组分成两部分, 并且根据题目的特殊规律 ,舍去一组,在另一组中继续重复进行操作,直到查找到点为止。
核心思路:特殊规律:升序数组(从中选取一个点与目标值比较:
目标值大于这个点,则一定大于左侧所有点,下一次选取点在右侧(往大的点去取)
目标值小于这个点,则一定小于右侧所有点,下一次选取点在左侧(往小的点去取))
若遇到等于情况:直接返回该点即可(就是要找的目标值)
若无法找到目标点:返回-1
细节:
- 此处求mid使用的计算方式是"防止数据溢出",直接(left+right)/2相加很可能造成数据溢出出现数组越界的问题
代码实现:
java
public int search(int[] nums, int target) {
int left=0;
int right=nums.length-1;
while(left<=right){
int mid=left+(right-left)/2;//防止溢出
if(nums[mid]>target){
right=mid-1;
}
if(nums[mid]<target){
left=mid+1;
}
if(nums[mid]==target){
return mid;
}
}
//只要能找到一定会在上面完成返回,运行到这,已经是找不到的情况
return -1;
}
总结:

根据特殊规律来制定选取点与目标值的判断条件即可。
本题的二分性:升序数组->元素数值大小递增,由此来分成一个大值部分,一个小值部分
模板代码:
java
while(left<=right){
if(//视特殊规律而定){
left=mid+1;
}
else if(//视特殊规律而定){
right=mid-1;
}
else{
return mid;
}
}
查找左,右端点的二分查找算法
题目要求:

题目要求在一个给定不递减数组 中,寻找目标值的第一个出现的下标,最后一个出现的下标。
可以归结为:"寻找由指定值组成的区间的左端点和右端点"。
题目解析以及核心思路:
题目解析:
相当于寻找左,右端点。 因此我们使用两次二分查找算法,来寻找左右端点。
解题准备:
- 二段性:若对于查找左端点,二段性为"小于t或者大于等于t";若对于查找右端点,二段性为"大于t或者小于等于t"
核心思路:1.查找左端点:
根据二段性:
当numsmid<目标t,向右区间(更大的数)去寻找
当numsmid>=目标t,向左区间(更小或者相同的数)去寻找==>当前指向数,可能就是目标值t,但是不知道其位置(前?中?末?),因此right不能越过mid(找首下标)
循环条件:left<right, 循环结果是left=right时,如果再继续循环会执行第二步骤,造成死循环
求中点操作:left+(right-left)/2。 数组元素个数为偶数时,取靠左的为中点,若选择靠右的为中点,会执行第二步骤,死循环
2.查找右端点:
根据二段性:
当numsmid>目标t,向左区间(更小或者相同的数)去寻找
当numsmid<=目标t,向右区间(更大或者相同的数)去寻找==>当前指向数,可能就是目标值t,但是不知道其位置(前?中?末?),因此left不能越过mid(找末尾下标)
循环条件:left<right, 循环结果是left=right时,如果再继续循环会执行第一步骤,造成死循环
求中点操作:left+(right-left+1)/2。 数组元素个数为偶数时,取靠右的为中点,若选择靠左的为中点,会执行第一步骤,死循环
补充: 循环结束,记得判断numsleft?=target,依此为返回数组赋值
代码实现:
java
class Solution {
public int[] searchRange(int[] nums, int target) {
//返回数组
int[] a={-1,-1};
//为空时直接返回[-1,-1]
if(nums==null||nums.length==0){
return a;
}
int left=0;
int right=nums.length-1;
//查找区间左端点
while(left<right){
int mid=left+(right-left)/2;
if(nums[mid]>=target){
right=mid;
}
else{
left=mid+1;
}
}
//此时left==right就是结果,与目标值比较相同则返回下标
if(nums[left]==target){
a[0]=left;
}
//查找区间右端点
left=0;
right=nums.length-1;
while(left<right){
int mid=left+(right-left+1)/2;
if(nums[mid]<=target){
left=mid;
}
else{
right=mid-1;
}
}
//此时left==right就是结果,与目标值比较相同则返回下标
if(nums[left]==target){
a[1]=left;
}
return a;
}
}
总结:
查找一个区间的左端点代码模板如左侧,查找一个区间的右端点代码模板如右侧

本人才疏学浅,若有错误还请诸位指正,希望本文能帮助到大家,后续还有关于二分查找应用的题目的博客文章,教大家如何使用模板,敬请期待。

根据二段性: