题目
题目详解
观察图片可以得到,根据旋转点分为了两个有序数组,
- 可以根据mid的所在地来进行不同的局部数组二分。
- 当然也可以直接先找到旋转点,然后找到target应该属于哪个区间,直接二分即可
先找旋转点的二分:
class Solution {
public:
int search(vector<int> &nums, int target) {
// 1. 先找到旋转点
// 2. 根据旋转点左右两段数据进行二分查找
//这种的最坏情况时间复杂度在O(n),找旋转点的时间,那还不如直接查找
int rotateIndex = -1;
int numsSize = nums.size();
for (int i = 1; i < numsSize; i++) {
if (nums[i - 1] > nums[i]) {
rotateIndex = i - 1;
break;
}
}
int left = 0;
int right = 0;
int mid = 0;
// 判断在那段有序数组中查找目标值
if (rotateIndex == -1) {
right = numsSize - 1;
} else {
// 旋转点右边有序数组
if (nums[numsSize - 1] >= target) {
left = rotateIndex + 1;
right = numsSize - 1;
// 旋转点左边有序数组
} else if (nums[0] <= target) {
left = 0;
right = rotateIndex;
} else {
return -1;
}
}
// 二分查找
mid = left + (right - left) / 2;
while (left <= right) {
if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
return mid;
}
mid = left + (right - left) / 2;
}
return -1;
}
};
直接的二分
//整体思路:将数组一分为二,其中一定有一个是有序的,另一个可能是有序,也能是部分有序。
//此时有序部分用二分法查找。无序部分再一分为二,其中一个一定有序,另一个可能有序,可能无序。就这样循环.
class Solution {
public:
int search(vector<int>& nums, int target) {
//得到数组长度
int n = (int)nums.size();
//特殊情况处理
if (!n) {
return -1;
}
if (n == 1) {
return nums[0] == target ? 0 : -1;
}
int l = 0, r = n - 1;
//开始二分,一般不是搜索边界的二分,都是取等号两边都闭区间,因为这样一旦弹出则必不存在target
while (l <= r) {
int mid = (l + r) / 2;
if (nums[mid] == target) return mid;
//如果mid大于首元素,说明处于左边有序局部数组中
if (nums[0] <= nums[mid]) {
//在该局部有序区间之内进行搜索
if (nums[0] <= target && target < nums[mid]) {
r = mid - 1;
} else {
l = mid + 1;
}//否则处于右边局部有序数组中
} else {
//落入该局部有序数组,继续搜索
if (nums[mid] < target && target <= nums[n - 1]) {
l = mid + 1;
} else {
r = mid - 1;
}
}
}
return -1;
}
};