Suppose a sorted array is rotated at some pivot unknown to you beforehand.
(i.e., 01 2 4 5 6 7 might become 4 5 6 7 0 1 2).
You are given a target value to search. If found in the array return its index,otherwise return -1.
You may assume no duplicate exists in the array.
思路:本题还是在考察二分查找。在一个经过旋转后的数组中寻找某个值,首先需要找到“旋转点”,比如在数组 4 5 6 7 0 1 2中,0元素的索引,也就是4,即是我们需要首先找到的“旋转点”。找到旋转点之后,整个数组就分为两个子数组,一是旋转点之前的数组,另一个是旋转点之后的数组。这两个数组都是按序递增的,因此只要分别在这两个数组上使用二分查找即可。
如何寻找旋转点,也需要使用二分查找的变种,二分查找之所以这么快,就是因为它每次都去掉了一半的可能性。
在寻找旋转点时,还是要看中点的值set[mid],如果set[left]<=set[mid],set[right]<=set[mid],比如上例中的45 6 7 0 1 2,这说明当前的中点在旋转点的左边,因此需要left = mid+1。
如果set[left]>=set[mid],set[right]>=set[mid],比如6 7 0 1 2 4 5,这说明当前的中点在旋转点的右边,因此需要right = mid-1。
如果set[left]<=set[mid]<=set[right],则说明当前的left和right已经完全处于某个子数组之中了,这时就是结束寻找的时候了,因left或者right都是针对上次的mid值前进或后退一步得来的,说明left或者right就是该子数组的边界,具体哪个才是要找的旋转点,就看本次到底是left向前走还是right向后走得到的,代码如下:
int findrotate(int *sets, int nums)
{
int left = 0, right = nums-1;
int mid, lastmid = -1;
while(left <= right)
{
mid = left + (right-left)/2;
if(sets[left] <= sets[mid] && sets[mid] <= sets[right]) break;
if(sets[mid] >= sets[left] && sets[mid] >= sets[right])
{
left = mid+1;
lastmid = mid;
}
else
{
right = mid-1;
lastmid = mid;
}
}
if(mid < lastmid) return lastmid;
else return lastmid+1;
}
int search(int* nums, int numsSize, int target)
{
int left[2], right[2];
int start, end, mid;
left[1] = findrotate(nums, numsSize);
left[0] = 0;
right[0] = left[1]-1;
right[1] = numsSize-1;
int i = 0;
for(i = 0; i < 2; i++)
{
start = left[i];
end = right[i];
while(start <= end)
{
mid = start + (end-start)/2;
if(nums[mid] == target) return mid;
if(nums[mid] < target)
{
start = mid+1;
}
else
{
end = mid-1;
}
}
}
return -1;
}