您的位置:首页 > 其它

LeetCode二分查找总结

2014-07-14 13:28 330 查看
对3道二分查找题的总结,来源于:soulmachine,code_ganker

Search Insert Position

Search in Rotated Sorted Array

Search in Rotated Sorted Array II

1.最基本的二分查找:

思路就是每次取中间,如果等于目标即返回;否则根据大小关系切去一半。

因此算法复杂度是O(logn),空间复杂度O(1)。

<span style="font-size:12px;">public class Solution {
public int searchInsert(int[] A, int target) {
int left=0;
int right=A.length-1;
while(left<=right){//【注意1】
int mid=(left+right)/2;
if(target==A[mid]) //find it!
return mid;
if (target<A[mid])//left half
right=mid-1;
else              //right half
left=mid+1;
}
return left;//should insert here【注意3】
}
} </span>


【注意1】while条件为left<=right,若找不到目标,最后一次操作是left和right指向同一index,执行一次循环体;结束时left>right,左右指针位置颠倒。

【注意2】先写leftHalf,再写rightHalf

【注意3】"以上实现有一个好处:循环结束时,如果没找到目标,那么left一定停在恰好比目标大的index上,right一定停在恰好比目标小的index上,比较推荐这种实现。"

2.旋转数组的查找I:

基本二分查找比较mid的值,这里比较target是否在区间,别无特殊。

不用纠结于Array怎么无序的,关注于旋转后一定有half是有序的。

<span style="font-size:12px;">public class Solution {
public int 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 mid;
if(A[left]<=A[mid]){   //leftHalf有序【注意1】
if(A[left]<=target && target<A[mid])//【注意2】
right=mid-1;
else
left=mid+1;
}
else{                //既A[left]>A[mid],leftHalf无序【注意3】
if(A[mid]<target && target<=A[right])
left=mid+1;
else
right=mid-1;
}
}
return -1;
}
}</span>


【注意1】条件必须是 A[left] <= A[mid],因为考虑到 left == mid 的case。例如:只写"<",那么考虑 A=[3,1], target=1 的测试用例,结果会是错误的"-1"。

【注意2】注意写区间时候按照[,)来写。判断target是否在有序的half里,思路较清楚。

至于为什么区间含left(或right)不含mid,因为target可能在两个边缘,如果在mid,就会直接return。

【注意3】条件写成 if ( A[left] > A[mid] ) -- else 也可以。

【注意4】关注于leftHalf是否有序,条件只能写成" if ( A[left] <= A[mid] ) -- else ",原因如上。(Soulmachine Ver.)

关注于rightHalf是否有序,条件可以写成" if ( A[mid] < A[right] ) -- else ",或" if ( A[mid] < A[right] ) -- else ",OJ均会accept。(Code_Ganker Ver.)

3.旋转数组的查找II:

和上题一样,只是因为元素重复,if(A[left]<=A[mid])不一定是有序的,需要将这个case拆解成两部分处理:

-若 A[left] < A[mid] ,按照有序处理;

-若 A[left] ==A[mid],left++,处理边缘再来查找就ok。

<span style="font-size:12px;">public class Solution {
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[left]<A[mid]){
if(A[left]<=target && target<A[mid])
right=mid-1;
else
left=mid+1;
}
else if(A[left]==A[mid]){
left++;
}
else{
if(A[mid]<target && target<=A[right])
left=mid+1;
else
right=mid-1;
}
}
return false;
}
}</span>
【注意1】"对left移动一步,直到边缘和中间不在相等或者相遇,这就导致了会有不能切去一半的可能。所以最坏情况(比如全部都是一个元素,或者只有一个元素不同于其他元素,而他就在最后一个)就会出现每次移动一步,总共是n步,算法的时间复杂度变成O(n)。"
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: