一.题意描述
Suppose a sorted array is rotated at some pivot unknown to you beforehand.
(i.e., 0 1 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.
数组中可能存在重复数字。
二.解题思路
与简单的二分查找相比,这道题需要多处理一个问题。因为数组是旋转过的排序数组,例如【5 6 6 7 1 2 3 3 4】,那么7为这一数组中的间断点,间断点两侧的数组都是排好序的数组,所以可以直接对这两部分的数组直接使用二分查找。
那么如何找到间断点?我们注意到间断点7大于等于数组中的首个节点5,间断点的下一个节点1小于等于首个节点5,事实上这也正是间断点的特点,我们可以依据这一特点对原数组进行二分查找,直至找到间断点。
在查找间断点的过程中需要注意一个问题,例如数组【1 3 1 1 1】(这也是LeetCode上的一个易错样例),这个数组的中间点1等于第一个点1,他的下一个节点1也等于第一个节点1,然而中间点却并不是间断点。这是一种特殊情况,在这种情况下需要手动将起始节点向后挪动一个,再继续进行二分查找。
在找到间断点之后,判断target数组出现在间断点的左区间还是右区间,问题退化成普通的二分查找,不再赘述。
三.代码实现
class Solution {
public:
int findPivot(vector<int>& nums) //查找中间点的函数
{
int start = 0;
int end = nums.size() - 1;
int mid;
while(1)
{
int mid = (start + end) / 2;
if(start == end)
return mid;
if(end == start+1)
{
if(nums[end] < nums[start])
return start;
else
return end;
}
if(nums[mid] == nums[start] && nums[mid + 1] == nums[start]) //上文中需要特判的情况
{
start++;
continue;
}
else if(nums[mid] >= nums[start] && nums[mid + 1] <= nums[start])
{
return mid;
}
else if(nums[mid] < nums[start])
{
end = mid - 1;
continue;
}
else
{
start = mid + 1;
continue;
}
}
}
bool binarySearch(vector<int>& nums, int start, int end, int target) //普通的二分查找函数
{
if(end < start)
return 0;
int mid = (start + end) / 2;
if(target == nums[mid])
return 1;
else if(target < nums[mid])
return binarySearch(nums, start, mid - 1, target);
else
return binarySearch(nums, mid + 1, end, target);
}
bool search(vector<int>& nums, int target) {
int pivot = findPivot(nums);
if(!nums.size())
return 0;
if(target >= nums[0])
return binarySearch(nums, 0, pivot, target);
else
return binarySearch(nums, pivot + 1, nums.size()-1, target);
}
};