假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [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
思路:两次二分。
1、第一次先找到数组中最大值所在的位置:
(1)如果是单调递增区间,最大值就在右端点。
(2)如果是有旋转点的区间:中点值如果比左端点值小的话,说明最大值在左半部分,中点值如果比左端点的值大的话,说明最大值在右半部分。不断重复该过程,直至找到最大值位置。
2、第二次找目标值位置:如果目标值的大小处于左端点与旋转点值之间,那么就对旋转点左半部分的递增区间进行二分查找,找到目标值。如果目标值的大小在旋转点值与右端点值之间,那么就对旋转点右半部分的递增区间进行二分查找,直至找到目标值。如果找不到的话返回-1。
class Solution { public: int search(vector<int>& nums, int target) { if (nums.empty()) return -1; int l = 0, r = nums.size() - 1, l1, r1, flag = -1; //flag记录数组中最大值坐标 while (l < r){ if (nums[l] <= nums[r]) break;//单调递增区间,直接跳出循环,右端点r就是最大值索引 else{ //有旋转点的区间,一直等到循环结束,l是最大值索引 int mid = l + (r - l) / 2; if (nums[mid] > nums[l]) l = mid; else if (nums[mid] <= nums[l]) r = mid-1; } } flag = (l < r ? r : l); if (target >= nums[0]){ //目标值落在左半递增区间 l1 = 0; r1 = flag; } if (target < nums[0]){//目标值落在右半递增区间 l1 = flag + 1; r1 = nums.size() - 1; } while (l1 <= r1){//在递增区间内使用二分查找找到目标值 int mid1 = l1 + (r1 - l1) / 2; if (nums[mid1] > target) r1 = mid1 - 1; if (nums[mid1] < target) l1 = mid1 + 1; if (nums[mid1] == target) return mid1; } return -1;//如果找不到的话返回-1 } };