这道题麻烦的地方就是不能像没有duplicate时候直接判断有没有bump。
所以,分成三种情况,如果 A[left]<A[mid] 或者 A[left] > A[mid],都可以直接判断左边有没有bump,然后根据左边或者右边的range来决定下一步去哪边。
如果A[left]==A[mid],则无法决定左右两边是range还是bump,所以略过left,移动到下个点进行判断。另一种方法是,利用递归,去搜查mid左右两边,因为此时两边都有可能有target,但比较麻烦,就没有实现了,而且既然还是要搜查整个数组,略过left是比较简单的方法了。
优化前代码如下:
public boolean search(int[] A, int target) {
int left = 0;
int right = A.length-1;
while(left<=right){
int mid = (left+right)/2;
if(A[mid]==target) return true;
if(A[mid]>A[left]){
if(A[left]<=target && A[mid]>target){
right = mid-1;
}
else{
left = mid+1;
}
}
else if(A[mid]<A[left]){
if(A[mid]<target && A[right]>=target){
left=mid+1;
}
else{
right = mid-1;
}
}
else{
left++;
}
}
return false;
}
没有太多duplicates的话应该是O(lgn),如果很多的话就是O(n),这时候跟直接遍历数组来找时间复杂度就一样了
唯一可以优化的是,当A[left]==A[mid],无法判断左边的情况,可以此时看看右边的情况,如果右边是range,就可以判断是不是应该去右边继续查找,如果右边是bump,则左边肯定是连续的相等的值而不可能是bump了,就不用去左边找了,如果右边两个值也相等,则两边都得找,因为两边可能有一个是bump,另一个是连续相等的值。优化后对大量重复数组有一点提升。
优化后代码如下:
public boolean search(int[] A, int target) {
int left = 0;
int right = A.length-1;
while(left<=right){
int mid = (left+right)/2;
if(A[mid]==target) return true;
if(A[mid]>A[left]){
if(A[left]<=target && A[mid]>target){
right = mid-1;
}
else{
left = mid+1;
}
}
else if(A[mid]<A[left]){
if(A[mid]<target && A[right]>=target){
left=mid+1;
}
else{
right = mid-1;
}
}
else{
if(A[mid]<A[right]){
if(A[mid]<target && target<=A[right]) left = mid+1;
else right = mid-1;
}
else if(A[mid]>A[right]) left = mid+1;
else if(A[mid]==A[right]) left++;
}
}
return false;
}