题目:
33. 搜索旋转排序数组
解题思路:
数组经过旋转后,从中间分开,一定有一部分是有序的,如示例中从6分开后数组变成[4, 5, 6]和[7, 0, 1, 2, 3],此时左半部分是有序的。这启示我们可以在常规二分查找的时候查看当前 mid 为分割位置分割出来的两个部分 [l, mid] 和 [mid + 1, r] 哪个部分是有序的,并根据有序的那个部分确定我们该如何改变二分查找的上下界,因为我们能够根据有序的那部分判断出 target 在不在这个部分:
- 如果 [l, mid - 1] 是有序数组,且 target 的大小满足 [nums[l],nums[mid]),则我们应该将搜索范围缩小至 [l, mid - 1],否则在 [mid + 1, r] 中寻找。
- 如果 [mid, r] 是有序数组,且 target 的大小满足 (nums[mid+1],nums[r]],则我们应该将搜索范围缩小至 [mid + 1, r],否则在 [l, mid - 1] 中寻找。
class Solution {
public:
int search(vector<int>& nums, int target) {
int n = (int)nums.size();
if(!n) return -1;
if( n == 1) return target == nums[0] ? 0 : -1;
int left = 0, right = n - 1;
while (left <= right) {
int mid = left + ((right - left) >> 1);
if(nums[mid] == target) return mid;
if(nums[0] <= nums[mid]) {//mid在左边的有序区间内
if(nums[0] <= target && target < nums[mid]){//target与mid同在左边有序区间
right = mid -1;
}
else {//target在[mid, n-1]这个单调区间内,此时向右收缩
left = mid + 1;
}
}else {//mid在第二个有序区间
if(nums[n - 1] >= target && nums[mid] < target){//target也在第二个有序区间
left = mid + 1;
}else{//target在左边的有序区间,此时向左收缩
right = mid - 1;
}
}
}
return -1;
}
};