难度:中等
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [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.empty())
return -1;
if(nums.size() == 1)
{
if(target == nums[0])
return 0;
else
return -1;
}
int min_index = search_min(nums);//返回旋转数组最小值位置
//将旋转数组分成两个升序数组,看target在哪个数组范围内查找,都不在的话,返回-1
if(target >= nums[min_index] && target <= nums[nums.size()-1])
return two_find(nums,min_index,nums.size()-1,target);
else if(min_index-1 >= 0 && target <= nums[min_index-1] && target >= nums[0])
return two_find(nums,0,min_index-1,target);
else
return -1;
}
//二分法查找,找出旋转数组的最小值位置
int search_min(vector<int>& nums)
{
int left = 0;
int right = nums.size()-1;
while(left < right)
{
if(right - left == 1)
break;
int mid = left + ((right-left)>>1);
if(nums[left] < nums[mid])
{
left = mid;
}else if(nums[right] > nums[mid])
{
right = mid;
}
}
return nums[left] > nums[right] ? right:left;
}
//二分法查找,找出目标位置
int two_find(vector<int>& nums, int start, int end, int target)
{
int left = start;
int right = end;
while(left <= right)
{
int mid = left + ((right-left)>>1);
if(nums[mid] < target)
{
left = mid + 1;//注意是mid+1和下面的mid-1
}else if(nums[mid] > target)
{
right = mid - 1;
}else{
return mid;
}
}
return -1;
}
};
int main()
{
Solution solution;
vector<int> nums = { 4, 5, 6, 7, 0, 1, 2 };
int target = 2;
cout << solution.search(nums, target) << endl;
system("pause");
return 0;
}