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; }