题目:33. Search in Rotated Sorted Array
Suppose an array sorted in ascending order 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.
Your algorithm's runtime complexity must be in the order of O(log n).
Example 1:
Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4
Example 2:
Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1
题意:
给定一个数组,数组里的内容为一个有序数列顺序往左移动了若干个位置(如example1 即为顺序左移3个位置)。查找给定元素target是否存在数组中,若存在则返回对应下标,否之返回-1;要求时间复杂度为O(log n);
分析:
常规遍历搜索可以解答此题,但是遍历一次时间复杂度为O(n),所以需要简化一些不必要的遍历;而且题目要求时间复杂度为O(logn) 即二分查找的时间复杂度完成即可。
同时本题也可以理解为 两个有序数列拼接在一起,所以可以先简单找回原来两个数列拼接的位置,然后进行二分查找,步骤如下:
- 特例判断,如果最左端的元素小于最右端的元素,即可说明此时数列为全部有序,因此对整个数列二分查找即可。
- 如果不是上述全部有序,那么只要找到第i个元素小于第i-1个元素的位置,就可以获得数列拼接的位置。并且在查找拼接位置的过程中可以和target进行比较,如果找到target元素,则可以直接返回对应下标;当找到拼接位置时,也可以说明要找的元素target只可能存在于后面的一个数列中,因此直接在后面的数列中进行二分查找即可。
- 实现如下:
Code:
class Solution {
public:
int binsearch(vector<int>&nums, int left, int right, int target){
while(left<=right){
int mid = (left+right)/2;
if(nums[mid]==target){
return mid;
}else if(nums[mid]>target){
right = mid-1;
}else{
left = mid+1;
}
}
return -1;
}
int search(vector<int>& nums, int target) {
int len = nums.size()-1;
if(len<0)return -1;
if(nums[0] == target) return 0;
int left=0,right=len;
if(nums[left] < nums[right])
return binsearch(nums, left, right, target);
for(int i=1;i<=len;++i){
if(nums[i] == target)return i;
if(nums[i]<nums[i-1]){
return binsearch(nums, i, right, target);
}
}
return -1;
}
};
Result:
Runtime: 8 ms, faster than 99.74% of C++ online submissions for Search in Rotated Sorted Array.
Memory Usage: 9.9 MB, less than 42.02% of C++ online submissions for Search in Rotated Sorted Array.
Note: 可以发现以上代码还可以进一步优化,即在查找拼接点的时候使用二分查找可以更加的高效。