假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7]
可能变为 [4,5,6,7,0,1,2]
)。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1
。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。
示例 1:
输入: nums = [4,5,6,7,0,1,2]
, target = 0
输出: 4
示例 2:
输入: nums = [4,5,6,7,0,1,2]
, target = 3
输出: -1
分析:
先使用二分查找,找到在哪一个点旋转的
找到旋转点后就能将数组分为两段有序的数组
在这两段有序数组上使用二分查找,找到 target 数字的位置
程序结束
class Solution {
public:
int search(vector<int>& nums, int target) {
if(nums.size() == 0)
return -1;
// 先找出从哪里旋转了,即查找最小值,然后在从那一半数据里面二分查找那个数据
int mid = get_min(nums);
// 先确定是在左半段查找还是在右半段查找
return (target > nums[nums.size()-1])?
binary_search(nums,0,mid-1,target):binary_search(nums,mid,nums.size()-1,target);
}
// 二分查找,返回下标
int binary_search(vector<int>& nums, int left, int right, int target){
int mid;
while(left <= right){
mid = (left + right)/2;
if(nums[mid] == target)
return mid;
if(nums[mid] < target)
left = mid + 1;
else
right = mid - 1;
}
return -1;
}
// 获得最小值的下标
int get_min(vector<int>& nums){
int mid, left, right, end;
left = 0;
right = end = nums.size() - 1;
while(left <= right){
mid = (left + right)/2;
if(left == right)
break;
// 最小值在 mid 的左边
if(nums[mid] <= nums[end]){
// 注意这里绝对不能 -1 ,如果 mid 指向的就是最小值,减一就得不到正确结果
right = mid;
}else{
// 在右边
left = mid + 1;
}
}
return mid;
}
};