题目描述
假设按照升序排序的数组在预先未知的某个点上进行了旋转。( 例如,数组 [0,1,2,4,5,6,7]
可能变为 [4,5,6,7,0,1,2]
)。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1
。
你可以假设数组中不存在重复的元素。你的算法时间复杂度必须是 O(logn)
级别。
示例 1
:
输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4
示例 2
:
输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1
第一种方法
首先对要查找的区间分情况对待
代码
class Solution {
public:
int search(int A[], int n, int target) {
int l = 0;
int r = n-1;
while(l <= r)
{
int mid = l+(r-l)/2;
if(A[mid] == target)
return mid;
//这个条件判断说明要查找的区间已经是一段单独的递增区间了
//可以直接使用传统的二分查找
if(A[l] <= A[r])
{
if(A[mid]>target)
r=mid-1;
else if(A[mid]<target)
l=mid+1;
}
else
{//到这一步骤时说明要查找的范围包括两段递增的区间
//这个条件判断说明mid在第一段递增区间
if(A[mid]>=A[l])
{
if(A[l]<=target && target<A[mid])
r = mid-1;
else
l=mid+1;//排除掉
}
else//说明mid在第二段递增区间
{
if(A[mid]<target && target<=A[r])
l = mid+1;
else
r=mid-1;//排除掉
}
}
}
return -1;
}
};
第二种方法
如果查找的范围包含两段递增区间,mid会将之分为一半递增,一半没有单调性,如果查找的范围已经为一段递增区间,mid会将之分为两半都是递增的,故不管哪种情况,mid会将之分成的两半中至少一半是递增的,如果我们能排除目标值不在这一半递增区间中,那我们就可以转换到另一半中查找了
要点:由实例观察总结出规律,进而落实到代码实现上
代码
class Solution {
public:
int search(vector<int>& nums, int target) {
int n = nums.size();
int l = 0;
int r = n-1;
while(l <= r)
{
int mid = l+(r-l)/2;
if(nums[mid] == target)
return mid;
//首先判断前半段是否是单调的,如果前半段不单调,那么后半段一定单调
if(nums[l] <= nums[mid])
{
if(nums[l] <= target && target < nums[mid])
r = mid - 1;
else//排除掉
l = mid + 1;
}
else
{
if(nums[mid] < target && target <= nums[r])
l = mid + 1;
else//排除掉
r = mid - 1;
}
}
return -1;
}
};