循环有序数组的查找
循环有序数组:
把一个有序数组从某个(未知)位置处截为两段,把前一段放到后一段的后面(数组元素两部分分别有序)
采用二分查找,时间复杂度要求O(log n)
主要难点:
二分查找时左右边界的确定
确定分割点之后,前半段和后半段中必然有一部分有序:1
2
3
4
5
6
7
8if(nums[first] <= nums[mid]) //前半部有序
{
//前半段有序时,判定target是否在前半段
}
else //后半部有序
{
//后半段有序时,判定target是否在后半段
}
完整代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28class Solution {
public:
int search(vector<int>& nums, int target) {
int first = 0;
int last = nums.size();
while (first != last) {
const int mid = first + (last - first) / 2;
if (nums[mid] == target) return mid;
if (nums[first] <= nums[mid]) {
if (nums[first] <= target && target < nums[mid]) { // 改进:将target与first的判等独立出来
last = mid;
} else {
first = mid + 1;
}
} else {
if (nums[mid] < target && target <= nums[last - 1]) { // 改进:将target与last-1的判等独立出来
first = mid + 1;
} else {
last = mid;
}
}
}
return -1;
}
};
若数组中允许存在重复元素:
nums[first] <= nums[mid]时,判断前半段有序的假设不再成立。如[2,3,4,2,2,2,2]。
解决:把条件拆分开
1 | if (nums[first] < nums[mid]) { |