Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
(i.e., [0,0,1,2,2,5,6] might become [2,5,6,0,0,1,2]).
You are given a target value to search. If found in the array return true, otherwise return false.
Example 1:
Input: nums = [2,5,6,0,0,1,2], target = 0
Output: true
这是33题的变体,也是rotate一个升序数组,区别是可以有重复的数字
思路:
binary search
比如[0, 1, 2, 3, 4, 5, 6] 翻转成 [3, 4, 5, 6, 0, 1, 2]
nums[left] = 3, nums[right] = 2, nums[mid] = 6,
可以看出当nums[mid] < nums[right]时,右半边是升序的,
当nums[mid] > nums[right]时,左半边是升序的。
当判断完哪半边升序之后,我们要判断target在不在这半边里面,
比如现在右半边升序,需要判断target是不是满足nums[mid] < target <= nums[right], (左边不是<=是因为如果=,直接就返回true了),如果满足,left = mid + 1, 接下来在右半边搜索;如果不满足这个条件,则需要在左半边搜索,right = mid - 1。
左半边升序的情况一样的。
因为本题允许重复元素的出现,还有一种情况,nums[mid] == num[right] (也可以和nums[left]比较)。
这种情况比如[1, 0, 1, 1, 1], 这里nums[left] = 1, nums[right] = 1, nums[mid] = 1。
如果nums[mid] 和 nums[right]比,它们相等,需要right --;
如果nums[mid] 和 nums[left]比, 它们相等, 则需要left ++。
时间复杂度O(logn), 最差O(n)
下面代码是nums[mid] 和 nums[right]比。
public boolean search(int[] nums, int target) {
int n = nums.length;
int left = 0;
int right = n - 1;
while(left <= right){
int mid = left + (right - left) / 2;
if(nums[mid] == target) return true;
if(nums[mid] < nums[right]) { //右半边升序
if(nums[mid] < target && target <= nums[right]) left = mid + 1; //target在右半边
else right = mid - 1;
} else if(nums[mid] > nums[right]) { //左半边升序
if(nums[left] <= target && target < nums[mid]) right = mid - 1; //target在左半边
else left = mid + 1;
} else {
right --; //如果前面if是nums[mid]和nums[left]比,则left ++
}
}
return false;
}
虽然上面是binary search, 但其实测试的时候发现线性搜索更快。
public boolean search(int[] nums, int target) {
int n = nums.length;
for(int i = 0; i < n; i++) {
if(nums[i] == target) return true;
}
return false;
}