33. 搜索旋转排序数组
二分法
将数组一分为二,则一定有 一部分是有序的,一部分是无序的 4 5 6 7 0 1 2
- 如果
nums[r] > nums[mid]
则右边一定有序 0 1 2(7_mid 0 1 2_r)
- 如果
nums[l] < nums[mid]
则左边一定有序 4 5 6 74_l 5 6 7 0_mid
- 对有序部分的首尾元素进行判断,
nums[mid] < target && nums[r] >= target
右边有序,且目标值大于队首 小于队尾,则一定在 有序部分中。 否则在无序部分中,
思路:如果中间的数小于最右边的数,则右半段是有序的,若中间数大于最右边数,则左半段是有序的,我们只要在有序的半段里用首尾两个数组来判断目标值是否在这一区域内,这样就可以确定保留哪半边了
class Solution {
public:
int bis(const vector<int>& nums,int l,int r,int target){
if(l>r) return -1;
int mid = l+(r-l)/2;
if(nums[mid] == target) return mid;
if(nums[r] > nums[mid]){ //right
if(nums[mid] < target && nums[r] >= target)
return bis(nums,mid+1,r,target);
else
return bis(nums,l,mid-1,target);
}else{
if(nums[mid] > target && nums[l] <= target )
return bis(nums,l,mid-1,target);
else
return bis(nums,mid+1,r,target);
}
}
int search(vector<int>& nums, int target) {
int len = nums.size();
if(!len) return -1;
int index = bis(nums,0,len-1,target);
return index;
}
};
// 非递归 写法
int search(vector<int>& nums, int target) {
int len = nums.size();
if(!len) return -1;
int l=0,r=len-1;
while(l<=r){
int mid = (l+r)/2;
if(nums[mid] == target) return mid;
if(nums[r] > nums[mid]){
if(nums[mid] < target && nums[r] >= target){
l = mid+1;
}else
r = mid-1;
}else{
if(nums[mid] > target && nums[l] <=target ) r = mid-1;
else l = mid+1;
}
}
return -1;
}
11.旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2]
为 [1,2,3,4,5]
的一个旋转,该数组的最小值为1。
- 如果中间的数小于右边的数,则右边有序 在左半段 继续查找
- 如果中间数 大于 左边的数,则左边有序 在右边段 继续查找
- 如果相等,则缩小搜索区间(去重)
2 2 2 0 1
class Solution {
public:
int minArray(vector<int>& numbers) {
// for(int j=numbers.size()-1;j>=1;j--){
// if(numbers[j-1] > numbers[j] ) return numbers[j];
// }
// return numbers[0];
int l=0,r=numbers.size()-1;
while(l<r){
int mid = (r+l)/2;
if(numbers[r] > numbers[mid])
r = mid;
else if(numbers[r] < numbers[mid])
l = mid+1;
else r--;
}
return numbers[l];
}
};