二分搜索的写法

二分搜索框架

int L,R,key;
while(L<=R)
{
    int mid=(L+R)>>1;
    if(a[mid]<key or a[mid]<=key)
        L=mid+1;
    else
        R=mid-1;
}
return L or R;

问题

二分搜索大家都很熟悉。如果待查区间内只有一个key值,要求找出key,那么一切都很容易。

但是如果有多个key,或者没有key,在不依赖现有库函数的情况下,怎么做到返回第一个key的位置,或最后一个key的位置,或者第一个大于key的位置此类的要求呢?

解决

其实很简单,只需要关注两个部分,一个是比较,另一个是返回值。

比较的控制

  1. 假设区间内有key,那么a[mid]<=key的写法会使得左端点一直向右移动。这样当L==R时,找到的就是最后一个key的位置。

    同理,a[mid]<key的写法会使得右端点向左移动,当L==R时,找到的就是第一个key的位置。

  2. 若区间内没有key,那么两种写法是等价的,因为不存在a[mid]==key的情况。

返回值的问题

​ 注意到,二分搜索结束的条件是L>R,那么最后的状态一定是LR的右边,二者相邻。

  1. 如果有key,那么根据上文中所述的写法的不同,会有两种情况。

    1.1 R指向最后一个keyLR右侧。

    1.2 L指向第一个keyRL左侧。

  2. 如果没有key。那么只有一种情况,即L指向第一个大于key的元素,R指向最后一个小于key的元素。

至此问题就解决了,只需要控制这两部分,就可以实现任意一种二分搜索的变体。

示例

  1. 查找第一个大于key的元素位置(类似stl的upper_bound的功能)

    int L,R,key;
    while(L<=R)
    {
        int mid=(L+R)>>1;
        if(a[mid]<=key)
            L=mid+1;
        else
            R=mid-1;
    }
    return L;
    
  2. 查找第一个key的位置,若不存在,则返回第一个大于key的元素位置(类似stl的lower_bound的功能)

    int L,R,key;
    while(L<=R)
    {
        int mid=(L+R)>>1;
        if(a[mid]<key)
            L=mid+1;
        else
            R=mid-1;
    }
    return L;
    
  3. 查找最后一个小于等于key的元素的位置

    int L,R,key;
    while(L<=R)
    {
        int mid=(L+R)>>1;
        if(a[mid]<=key)
            L=mid+1;
        else
            R=mid-1;
    }
    return R;
    
posted @ 2021-06-22 22:50  cryingrain  阅读(62)  评论(0编辑  收藏  举报