二分法查找
我们将数组从中间分开成左右两部分的时候,一定有一部分的数组是有序的。
这启示我们可以在常规二分查找的时候查看当前 mid 为分割位置分割出来的两个部分 [l, mid] 和 [mid + 1, r] 哪个部分是有序的,并根据有序的那个部分确定我们该如何改变二分查找的上下界,因为我们能够根据有序的那部分判断出 target 在不在这个部分:
1、如果[l, mid - 1] 是有序数组,且 target 的大小满足nums[l]<=target<nums[mid],则我们应该将搜索范围缩小至 [l, mid - 1],否则在 [mid + 1, r] 中寻找。
2、如果 [mid, r] 是有序数组,且 target 的大小满足nums[mid]<target<=nums[r],则我们应该将搜索范围缩小至[mid + 1, r],否则在 [l, mid - 1] 中寻找。
假如target存在于数组中,那最后一定会缩小到target=nums[mid],就可以返回mid
特殊情况:
1、当len=0,直接返回-1
2、当len=1,比较nums[0]是否等于target,若相等则返回0,不相等则返回-1
class Solution {
public:
int search(vector<int>& nums, int target) {
int len=nums.size();
if(len==0) return -1;
if(len==1){
return nums[0]==target?0:-1;
}
int l=0;
int r=len-1;
while(l<=r){
int mid=(l+r)/2;
if(nums[mid]==target){ //找到了target直接返回
return mid;
}
if(nums[mid]>=nums[l]){ // 左边有序 注意这里是大于等于
if(nums[l]<=target&&nums[mid]>target){ //且target在左边有序范围里
r=mid-1; //二分法,缩小范围到左边
}
else l=mid+1; //target在右边,缩小范围到右边
}
else{
if(nums[mid]<target&&nums[r]>=target){ //右边有序且target在右边有序范围里
l=mid+1; //target在右边,缩小范围到右边
}
else r=mid-1; //二分法,缩小范围到左边
}
}
return -1;
}
};