二分查找

二分查找是既简单又困难的部分,如果序列有序,我们可以使用二分查找,总结如下:

一、递归的二分查找

递归的方法来解决二分查找。

int bsearch(vector<int>&nums,int low,int high,int target)
{
    if(low>high)
        return -1;
    int mid=(low+high)/2;
    if(nums[mid]>target)
        return bsearch(nums,low,mid-1,target);
    if(nums[mid]<target)
        return bsearch(nums,mid+1,high,target);
    return mid;
}

二、迭代的二分查找

除了递归,还可以用迭代的方式进行二分查找,前提也是序列有序。

int bsearch(vector<int>&nums,int low,int high,int target)
{
    while(low<=high)
    {
        int mid=(low+high)/2;
        if(nums[mid]>target)
            high=mid-1;
        if(nums[mid]<target)
            low=mid+1;
        else
            return mid;
    }
    return -1;//not found
}

三、二分查找求上下界

上述两种情况是标准的二分查找,要求序列中元素有序且无重复,假如现在题目中序列存在重复元素,要求重复元素的上下界。例如 [1,2,2,3]求2的上下界(索引),为(1,2)

(1)二分查找求下界

由于计算mid的时候总是向下去整,因此,计算下界的时候需要对mid计算做一个简单的处理。

int lowerbounds(vector<int>&nums,int low,int high,int target)
{
    if(low>high||nums[low]>=target)
        return -1;
    int mid = (low+high + 1)/2;
    while(low<high)
    {
        if(nums[mid]<target)
            low=high;
        else
            high=mid-1;
        mid=(low+high+1)/2;
    }
    return mid;
}

(2)二分查找求上界

跟求下界类似。

int upperbounds(vector<int>&nums,int low,int high,int target)
{
    if(low>high||nums[high]<=target)
        return -1;
    int mid=(low+high)/2;
    while(low<high)
    {
        if(nums[mid]>target)
            high=mid;
        else
            low=mid+1;
    }
    return mid;
}

但是考虑一些特殊情况,例如序列为[5,5,5,5],target为5,这时我们计算出来lower和upper都为-1;或者例如序列为[1,2,3,4],target为5计算出来lower为3,upper为-1,为了排除这些特殊情况,在进行二分查找之前,往nums后面添加一个INT_MAX,这样保证始终有上界。

class Solution 
{
    private:
    int lowerbounds(vector<int>&nums,int target,int low,int high)
    {
        if(low>high||target<=nums[low])//不在范围
            return -1;
        int mid = (low+high+1)/2;
        while(low<high)
        {
            if(nums[mid]<target)
                low=mid;
            else
                high=mid-1;

            mid = (low+high+1)/2;
        }
        return mid;
    }
    int upperbounds(vector<int>&nums,int target,int low,int high)
    {
        if(low>high || target>=nums[high])//不再范围
        return -1;
        int mid = (low + high)/2;
        while(low<high)
        {
            if(nums[mid]>target)
                high=mid;
            else
                low=mid+1;
            mid=(low+high)/2;
        }
        return mid;
    }
    public:
    vector<int> searchRange(vector<int>& nums, int target) {
        nums.push_back(INT_MAX);
        vector<int>res(2,-1);
        int lower = lowerbounds(nums,target,0,nums.size()-1);
        if(nums[lower+1]==target)
        {
            res[0]=lower+1;
        }
        else
        {
            return res;
        }
        int upper=upperbounds(nums,target,0,nums.size()-1);
        res[1]=upper-1;
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值