传统二分查找的核心思想就是,在保证目标值在区间里的条件下,不断以1/2的规模进行收缩!!!!
注意:证明思路都一样,全都是left或right会不会越过某一值(一般是目标值)
一、基本的二分查找
int left=0,right=A.length-1,mid=0;
while(left<=right){
mid=(left+right)/2;
if(A[mid]==target){
break;
}else if(A[mid]>target){
right=mid-1;
}else if((A[mid]<target){
left=mid+1;
}
}
证明:如果有目标值,会返回目标值的下标
考虑序列:....7 8 9......查找8
只需要证明在找到8之前left,right永远不会越过8这个数,可用反证法证明。如果left由小于8的数指向了8之后的数,
那么left一定是执行了left=mid+1,那么A[mid]一定是小于8的,也就是说A[mid]最大只能是7,那么新的A[left]最多只能是
8,不可能超过8.right同理。
一句话总结就是[left,right] 区间里永远都包含8这个数,区间不断以1/2的规模收缩
证明:如果没有目标值,会返回小于目标值的元素中最接近目标值元素的下标,或者是大于目标值的元素中最接近目标值元素的下标
考虑序列: .....7 9.......查找8
只需要在循环时证明在[left,right]这个区间只要是一个正常的区间即left<right,left最多指向9,而left一旦指向了9,right就会不断往左边收缩,最后返回返回mid=9。同理 right最多指向7,如果right先指向了7,最终返回mid=7.
二、左边界的二分查找
int left=0,right=A.length-1,mid=0;
while(left<=right){
mid=(left+right)/2;
if(A[mid]<target){
left=mid+1;
}else{
right=mid-1;
}
}
证明:如果有目标值会返回最左侧目标值的下标或者其前驱的下标
考虑序列 .....7 8 8 8 9......
我们只需要证明,[left,right] 区间里永远都包含第一个8或者7这个数,而且区间不断以1/2的规模收缩
证明思路是left永远不会越过第一个8,right永远不会越过7,可用反证法证明,类比上面的证明
三、右边界的二分查找
int left=0,right=A.length-1,mid=0;
while(left<=right){
mid=(left+right)/2;
if(A[mid]<=target){
left=mid+1;
}else{
right=mid-1;
}
}