一.题意描述
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); } };