Question
Follow up for “Search in Rotated Sorted Array”:
What if duplicates are allowed?
Would this affect the run-time complexity? How and why?
Write a function to determine if a given target is in the array.
本题难度Medium。
【复杂度】
时间 O(N) 空间 O(1)
【思路】
本题是Search in Rotated Sorted Array的变形。在Search in Rotated Sorted Array中可以通过nums[start]<=nums[mid]
或nums[mid]<=nums[end]
判断两边是否为有序。但是在这里出现一个问题:比如左半边,如果nums[start]==nums[mid]
它是有序吗?对于:
[1 3 1 1 1]
左半边为1 3 1
,符合条件但并不有序。不过如果nums[start]<nums[mid]
,那么左半边仍然是有序的。因此,我们列出三种情况进行处理:
- 左半边有序。如果target在左半边范围内就只搜索左半边,否则只搜索右半边
- 右半边有序。如果target在右半边范围内就只搜索右半边,否则只搜索左半边
- 都不是。两边都要分别搜索
其本质就是增加了对第三种情况的处理(29-34行)
【注意】
我们在判断是否为有序时,比如对于左半边是:
nums[start]<nums[mid]
,不要写成nums[start]<nums[mid-1]
,这样有可能导致mid-1<0
超过范围在判断是否在其范围内,比如左半边是:
nums[start]<=target&&target<nums[mid]
不要写成target<nums[mid]
只判断一边,例如:[4 5 6 1 2 3],target=3
左半边为
4 5 6
,有序,而且3<6
,但3不在左半边。而对于有序数列而言,如果target<nums[mid]
,target是不可能再出现在右半边,所以可以单边判断。
【代码】
public class Solution {
public boolean search(int[] nums, int target) {
//require
int size=nums.length;
if(size<1)
return false;
//invariant
return helper(0,size-1,nums,target);
}
private boolean helper(int start,int end,int[] nums, int target){
//base case
if(end<start)
return false;
int mid=(start+end)/2;
if(nums[mid]==target)
return true;
if(nums[start]<nums[mid]){
if(nums[start]<=target&&target<nums[mid])
return helper(start,mid-1,nums,target);
else
return helper(mid+1,end,nums,target);
}else if(nums[mid]<nums[end]){
if(nums[mid]<target&&target<=nums[end])
return helper(mid+1,end,nums,target);
else
return helper(start,mid-1,nums,target);
}else{
if(helper(start,mid-1,nums,target))
return true;
else
return helper(mid+1,end,nums,target);
}
}
}
参考
Java 1ms binary search solution with comments
public class Solution {
public boolean search(int[] nums, int target) {
// note here end is initialized to len instead of (len-1)
int start = 0, end = nums.length;
while (start < end) {
int mid = (start + end) / 2;
if (nums[mid] == target) return true;
if (nums[mid] > nums[start]) { // nums[start..mid] is sorted
// check if target in left half
if (target < nums[mid] && target >= nums[start]) end = mid;
else start = mid + 1;
} else if (nums[mid] < nums[start]) { // nums[mid..end] is sorted
// check if target in right half
if (target > nums[mid] && target < nums[start]) start = mid + 1;
else end = mid;
} else { // have no idea about the array, but we can exclude nums[start] because nums[start] == nums[mid]
start++;
}
}
return false;
}
}