如果不要求时间复杂度的话,其实很简单。
可以先找到分界下标(其实就是最大值),这样就可以将原数组分为两个有序数组,在两个有序数组里分别查找就行,但是时间复杂度O(n)。
也可以:
- 找到最大值的下标 x;
- 所有元素下标 +x 偏移,超过数组范围值的取模;
- 利用偏移后的下标做二分查找;
- 如果找到目标下标,再作 -x 偏移,就是目标值实际下标。
时间复杂度也是O(n)。
上述方法主要都把精力放在了寻找最大值上面。
题目要求时间复杂度O(logn),自然是使用二分法了,**其实查找分界点可以在O(logn)**时间内完成:
- 在数组内二分法查找第一个小于首元素的位置,返回的值就是分界点
比如567123,二分法查找返回下标3:567123,1即为分界点。
既然有了分界点,根据target与数组首元素进行比较,就可以确定应该在哪个区间进行再一次的二分查找了:
class Solution {
public:
//二分法查找第一个小于首元素a[0]的元素
//返回的index即为分界点
int bsearch(vector<int> &a, int low, int high, int value){
while(low <= high){
int mid = low + ((high-low)>>1);
if(a[mid] < value){
if(mid == 0 || a[mid-1] >= value) return mid;
else high = mid-1;
}else low = mid+1;
}
return -1;
}
int bsearch_c(vector<int> &a, int low, int high, int value){
while(low <= high){
int mid = low + ((high-low)>>1);
if(a[mid] == value) return mid;
else if(a[mid] > value) high = mid-1;
else low = mid+1;
}
return -1;
}
int search(vector<int>& nums, int target) {
int n = nums.size();
if(nums.empty()) return -1;
auto index = bsearch(nums, 0, n-1, nums[0]);
// 数组有序
if(index == -1) return bsearch_c(nums, 0, n-1, target);
if(nums[0] > target ){ //在后半部分查找
return bsearch_c(nums, index, n-1, target);
}else{ //在前半部分查找
return bsearch_c(nums, 0, index-1, target);
}
}
};