自己的碎碎念(不用看)
朴素二分查找,在我自己目前看过的书中都只是简略的写过,而且大多数只有果没有因(当然肯定是我自己不聪明的成分),所以我一直想花时间把二分查找弄明白。
一直以来都是很搞不懂,为什么一个简单的大于号小于号就能决定查找的方向呢。这次我花了时间看了B站上一个名叫skywave的up主的视频搞明白了
主题部分
int bs(int *a , int l , int r , int target){
//第一个大于target出现的位置
while(l <= r){
int mid = (l + r)>>1;
if(a[mid] > target){
r = mid - 1;
}else{
l = mid + 1;
}
}
return l;
//最后一个小于等于target的位置 return r
}
- 下面我来仔细说这段代码,如果我们要找的是第一个大于target的位置,把 l , r l,r l,r都看作两个指针
- 在满足 r r r指针所指向的值大于 t a r g e t target target的时候, r r r指针就会不断地向着 l l l指针的方向靠拢
- 直到 r r r指针下一次移动到的方向不满足 > t a r g e t >target >target这个条件了
- 那么此时 a [ r ] < = t a r g e t a[r]<=target a[r]<=target那么下一步就执行else语句
- l l l指针不断向 r r r指针靠拢,直到相遇
- 因为相遇之后还不满足条件,所以继续执行else语句
- 然后这个时候 l l l指针超越了 r r r指针,因为 r r r指针指向的是最后一个小于等于 t a r g e t target target的位置,且 l l l指针比 r r r指针多了一位,那么此时一定是 l l l所指的元素位置一定是第一个大于 t a r g e t target target的位置,即 a [ l ] > t a r g e t a[l]>target a[l]>target;
int bss(int *a , int l , int r ,int target){
//最后一个小于target出现的位置
while(l <= r){
int mid = (l + r)>>1;
if(a[mid] >= target){
r = mid - 1;
}else{
l = mid + 1;
}
}
return r;
//第一个大于等于target的位置就return l
}
- 如果我们要找的是最后一个小于 t a r g e t target target出现的位置呢?
- 根据两个指针的特性相比,在中间值一直大于目标值的情况下,我们的最右端指针一直不断向左👈移动,直到他下一个指向的元素不满足这个条件
- 也就是说此时 r r r指针已经指向了一个小于 t a r g e t target target的元素的位置
- 以此类推,
l
l
l指针不断接近
r
r
r指针并最后超过
r
r
r指针一个位置成为一个指向第一个大于等于
t
a
r
g
e
t
target
target的值的位置
** l l l永远指向的是一个符合条件的位置,而 r r r永远指向一个非法的位置,也就是跟着他反着来,这才有了为什么大于小于决定了这个二分查找的方向。