33. Search in Rotated Sorted Array

一、题目


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.

You may assume no duplicate exists in the array.

二、分析


  rotated之后的数组是无序的。但是,它可以以最小值为界分为前后两个子数组,而这两个数组都是有序的。我们可以首先确定要找的数target在哪个子数组,然后在哪个子数组进行binary_search即可。

  1,找最小值所在位置

 1 int getMinIndex(vector<int>& nums) {
 2         int length = nums.size();
 3         if (length == 0)
 4             return 0;
 5         int left = 0, right = length -1, mid = 0;
 6 
 7         while (left < right) {
 8             if (nums[left] < nums[right])
 9                 //return nums[left];
10                 return left;
11             mid = left + (right - left) / 2;
12             if (nums[mid] <= nums[right])
13                 right = mid;
14             else
15                 left = mid + 1;
16         }
17         //return nums[left];
18         return left;
19     }

  2,binary_search

 1 int binary_search(vector<int> &nums, int target, vector<int>::iterator iterLeft, vector<int>::iterator iterRight) {
 2         while (iterLeft <= iterRight) {
 3             auto mid = iterLeft + (iterRight - iterLeft) / 2;
 4             if (*mid < target)
 5                 iterLeft = mid + 1;
 6             else if (*mid > target)
 7                 iterRight = mid - 1;
 8             else
 9                 return mid - nums.begin();
10         }
11         return -1;
12     }

  3, 找target的位置

 1  int search(vector<int>& nums, int target) {
 2         vector<int>::iterator iterLeft = nums.begin(), iterRight = nums.end() - 1;
 3         if (nums.size() == 0)
 4             return -1;
 5         if (*iterLeft < *iterRight) {   //array not be rotated
 6             return binary_search(nums, target, iterLeft, iterRight);
 7         }
 8         else {
 9             int index = getMinIndex(nums);
10             if (target <= *iterRight) {
11                 iterLeft += index;
12                 return binary_search(nums, target, iterLeft, iterRight);
13             }else {
14                 iterRight = iterLeft + index;
15                 return binary_search(nums, target, iterLeft, iterRight);
16             }
17         }
18     }

  4,总结前三点,总代码如下

 1 class Solution {
 2 public:
 3     int getMinIndex(vector<int>& nums) {
 4         int length = nums.size();
 5         if (length == 0)
 6             return 0;
 7         int left = 0, right = length -1, mid = 0;
 8 
 9         while (left < right) {
10             if (nums[left] < nums[right])
11                 //return nums[left];
12                 return left;
13             mid = left + (right - left) / 2;
14             if (nums[mid] <= nums[right])
15                 right = mid;
16             else
17                 left = mid + 1;
18         }
19         //return nums[left];
20         return left;
21     }
22 
23     int search(vector<int>& nums, int target) {
24         vector<int>::iterator iterLeft = nums.begin(), iterRight = nums.end() - 1;
25         if (nums.size() == 0)
26             return -1;
27         if (*iterLeft < *iterRight) {
28             return binary_search(nums, target, iterLeft, iterRight);
29         }
30         else {
31             int index = getMinIndex(nums);
32             if (target <= *iterRight) {
33                 iterLeft += index;
34                 return binary_search(nums, target, iterLeft, iterRight);
35             }else {
36                 iterRight = iterLeft + index;
37                 return binary_search(nums, target, iterLeft, iterRight);
38             }
39         }
40     }
41 
42     int binary_search(vector<int> &nums, int target, vector<int>::iterator iterLeft, vector<int>::iterator iterRight) {
43         while (iterLeft <= iterRight) {
44             auto mid = iterLeft + (iterRight - iterLeft) / 2;
45             if (*mid < target)
46                 iterLeft = mid + 1;
47             else if (*mid > target)
48                 iterRight = mid - 1;
49             else
50                 return mid - nums.begin();
51         }
52         return -1;
53     }
54 
55 };
View Code

三、另一种“非常规”解法


  首先,我们还是找到最小值的位置,也就是两个有序子数组的分界点,记为rot。然后,取rotated数组(长度为n)的mid,那么(rot+mid)%n即unrotated数组的真实mid位置。

  然后,对这个数组进行二分查找。

 1 class Solution {
 2 public:
 3     int search(int A[], int n, int target) {
 4         int lo=0,hi=n-1;
 5         // find the index of the smallest value using binary search.
 6         // Loop will terminate since mid < hi, and lo or hi will shrink by at least 1.
 7         // Proof by contradiction that mid < hi: if mid==hi, then lo==hi and loop would have been terminated.
 8         while(lo<hi){
 9             int mid=(lo+hi)/2;
10             if(A[mid]>A[hi]) lo=mid+1;
11             else hi=mid;
12         }
13         // lo==hi is the index of the smallest value and also the number of places rotated.
14         int rot=lo;
15         lo=0;hi=n-1;
16         // The usual binary search and accounting for rotation.
17         while(lo<=hi){
18             int mid=(lo+hi)/2;
19             int realmid=(mid+rot)%n;
20             if(A[realmid]==target)return realmid;
21             if(A[realmid]<target)lo=mid+1;
22             else hi=mid-1;
23         }
24         return -1;
25     }
26 };