1. 程式人生 > >二分思想

二分思想

就是 滿足 ace 循環 pan 區別 pre spa div

#include<cstdio>
using namespace std;
//二分查找
int bsrch(int l,int r,int k,int a[])
{
    int mid;
    while(l<=r){
        mid=(l+r)/2;
        if(a[mid]>k)r=mid-1;
        else if(a[mid]==k)return mid;
        else l=mid+1;
    }
    return -1;
}
//有序區間下界
//第一個大於等於k的元素的位置
int lowerBound(int l,int
r,int k,int a[]) { while(l<r){ int mid=(l+r)/2; if(a[mid]>=k)r=mid;//進入左子區間[l,mid] else l=mid+1;//進入右子區間[mid+1,r] } return l; } //有序區間上界
//第一個大於k的元素位置
int upperBound(int l,int r,int k,int a[]) { while(l<r){ int mid=(l+r)/2; if(a[mid]>k)r=mid;
else l=mid+1; } return l; } int main() { int a[]={1,2,3,3,3,3,3,4,5,6,7}; int l=0,r=10; int k=3; printf("%d\n",bsrch(0,10,k,a)); printf("%d\n",lowerBound(0,10,k,a)); printf("%d\n",upperBound(0,10,k,a)); while(1); }

這是三段非常相似的代碼。二分查找比較明確,難懂的是下面的兩段代碼。大體的思路沿襲二分的想法,區別就在於搜索左右子區間的條件不同。

可以註意到一個特點,lowerBound返回的下標對應的值一定大於等於k,循環結束的條件是l==r,所以滿足條件,upperBound類似。

寫成遞歸形式可能更容易理解,下面就是lowerBound的遞歸形式

int lowerBound_r(int l,int r,int k,int a[])
{
    if(l==r)return l;
    int mid=(l+r)/2;
    if(a[mid]>=k)return lowerBound_r(l,mid,k,a);
    else return lowerBound_r(mid+1,r,k,a);
}

從遞歸看返回的就是最左邊的大於等於k的值

類似得出upperBound的遞歸形式

int upperBound_r(int l,int r,int k,int a[])
{
    if(l==r)return l;
    int mid=(l+r)/2;
    if(a[mid]>k)return upperBound_r(l,mid,k,a);
    else return upperBound_r(mid+1,r,k,a);
}

返回最左邊的大於k的位置

二分思想