二分查找的不易错版本

有个视频讲二分法很不错,然后记录一下。

数组中的数不重复

这种就很简单,不过用视频中的方法写一下就是

int BinarySearch(vector<int> nums, int target) {
//vector<int> nums({1,2,3,4,5,6,8,9});
//int target = 5;
    int n = nums.size();
    int l = -1;
    int r = n;
    while(l + 1 != r) {
        int mid = l + (r - l) / 2;//一种防数值溢出的写法,正常就是(l + r) / 2
        if(nums[mid] > target) {
            r = mid;
        }
        else if(nums[mid] < target) {
            l = mid;
        }
        else   
            return mid;
    }
    return -1;
}

这里呢,有一些与平常写的二分法不同的地方

1、为什么while(l + 1 != r) 而不是正常的while(l < r)?

答:这里呢,是想要l 与 r不会指向同一个数据,这个在之后的数组中的数有重复的时会有用

2、为什么l = -1, r = n,而不是 l = 0, r = n-1?

答:我们看下面这个图,首先咱们记住l + 1 != r

如果我要找的值是1,那么循环进行后,只有r会动,r指到2的时候停止,那么,l处就不会被检验到。同理,如果找的是9的话,循环进行,只有l动,但也不会检验到9这个数。出现错误了就。所以,当l = -1, r = n的时候,就不会有这个问题。

3、那这个时候mid是否始终处于[0,n)内?

答:我们看一下mid的最小值和最大值

l_{min} = -1        这个是没问题的

r_{min} = 1           如果能够进入循环,那么l + 1 != r, r最小就是1了

mid_{min} = 0

r_{max} = n          这个也没什么问题

 l_{max} = n - 2   如果能够进入循环,那么最后一次循环就是 n - 2 了

mid_{max} = n - 1

总结:mid正好在这个区域内

4、能不能写成l = mid + 1,或者 r = mid - 1

答:我之前写二分法就被这个搞得头疼。在这里,这个代码中,不能这样写。

因为这个代码中,是不会检验到 l 和 r 所指的数值的。

想一想:mid = l 的条件是 l + 1 = r,但这样根本不会进入循环体。

所以如果未检验过的数值(即未被mid指中的数)就不要让l或者r指向了。

当然还可以这样解释,如果我想找4,但mid指到了3,用到 l = mid + 1,l就是4,但是不会检验到l,这个程序就出错了。

数组的数重复

问题对应位置
找到第一个大于等于5的元素位置2
找到最后一个小于5的元素位置1
找到第一个大于5的元素位置5
找到最后一个小于等于5的元素位置4

去解决这样的问题,l + 1 != r就有优势了,你可以用l或者r来输出相应位置。

这是找第一个大于等于5的元素位置代码。

int BinarySearch(vector<int> nums, int target) {
    int n = nums.size();
    int l = -1;
    int r = n;
    while(l + 1 != r) {
        int mid = l + (r - l) / 2;
        if(nums[mid] >= target) {
            r = mid;
        }
        else if(nums[mid] < target) {
            l = mid;
        }
    }
    return r;
}

通过改变不等号和输出的l或者r。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值