33. 搜索旋转排序数组
这一题也比较简单,刚开始拿到的时候,觉得有点棘手,不敢下手,后来看了下解析,明白了思路后,就自己写了,然后一遍过了。
总的思路: 二分查找+分类讨论
1. 传统的二分法
传统的二分法十分简单,首先找到中间的,比较是否等于目标值,如果等于则返回,如果不等,则相应调整上边界或者下边界。一个简单的代码如下,但是要注意一些细节。
int BinarySearch(int nums[], int target)
{
int low = 0, high = sizeof(nums) - 1, mid;
while (low <= high) {
mid = (low + high) / 2;
if (nums[mid] == target) {
return mid;
}
else if (nums[mid] > target) {
high = mid - 1;
}
else
low = mid + 1;
}
}
2. 旋转数组的二分
此题中的数组经过了旋转,跟传统的二分就有区别。但是仍然以二分法为基础,在此基础上,情况相较于传统的更多,需要更详细的分类讨论。主要有以下几种情况:
(1) 每次划分的中间值刚好等于目标值,则直接返回;
示例如下:目标值为6。
3 | 4 | 5 | 6 | 7 | 0 | 1 | 2 |
(2) 如果不是,那么分为几种情况:
2.1 如果左半边是有序的
2.1.1 如果目标值在这中间,那么应该在左边寻找,此时调整上边界到 mid - 1;
2.1.2 如果目标值不在这中间,那么在右边寻找,调整下边界到 mid+1;
4 | 5 | 6 | 7 | 0 | 1 | 2 | 3 |
2.2 如果左半边是无序的(新的旋转数组)
同样判断目标值是否在这中间(怎么判断:如果目标值大于最左边的或者目标值小于mid处的值,那么即在这之间);如果在,则调整上边界,如果不在则调整下边界。
6 | 7 | 0 | 1 | 2 | 3 | 4 | 5 |
### 具体代码 具体的代码如下:
class Solution {
public:
int search(vector<int>& nums, int target) {
// 直接循环肯定超时
// 所以直接二分法
bool flag = false;
int n = nums.size();
int low = 0, high = n - 1, mid;
while (low <= high) { //循环条件
mid = (low + high) / 2;
int m = nums[mid];
if (m == target) {
flag = true;
break;
}
else {
if (nums[low] <= nums[mid]) { // 左边是有序的
if (nums[low] <= target && nums[mid] >= target) { //且target在这之间,那么在这部分二分查找
high = mid - 1;
}
else { // 否则在右边查找
low = mid + 1;
}
}
else { //左边是无序的
if (target >= nums[low] || target <= nums[mid]) { // 若大于最左边的或小于中间的,则在左边
high = mid - 1;
}
else { // 否则在右边
low = mid + 1;
}
}
}
}
if(flag)
return mid;
else
return -1;
}
};
总的来说,关键是要弄清楚几种分类情况。