个人比较喜欢的最左(最右)二分查找写法

我们偶尔会遇到这样的二分查找问题,它的元素有重复,我们需要找到这个元素下标最小和最大的位置。或者它不是一种精确地查询,比如问一个排序数组中,大于等于6的最小数值是多少。

面对这样的问题呢,我们的核心思路仍然是用二分法,只不过我们查找到符合条件的元素后不会立刻停止,而是会继续查找,缩短范围。

它的核心还是判断。

举个例子,假设在[L, R]区间内进行二分查找,成立条件为Condition(X) == True。因此我们可以套用这样的模板

int l = L;
int r = R;
int res = -1;
while (l <= r)
{
    int m = (l + r) / 2;
    if (condition(M))
        res = m;
        缩短范围
    else
        缩短范围
}
if (res != -1)
    找到范围内符合条件的结果
else
    范围内无符合条件的结果

注意这个res变量,这就是我喜欢这种写法的地方。它不用靠循环结束后的l或者r来确定最终停在哪个位置。它始终保存着最后一次符合条件的结果的值。仔细思考思考,非常直观。

然后就是condition和缩短范围的写法。这里就要区分要找最小还是最大的概念。它决定了区间缩放的方向。

假如以上边的例子为例,我要找到大于等于6的最小值

那就应该这么写

if (m >= 6)
    res = m;
    r = m - 1;
else
    l = m + 1;

如果要找到严格等于6的最左值或严格等于6的最右值,核心就是在找到元素时不要停止查找,而是缩短范围即可

最右
if (m == 6)
    res = m;
    l = m + 1;
else if (m < 6)
    l = m + 1;
else
    r = m - 1;

最右
if (m == 6)
    res = m;
    r = m - 1;
else if (m > 6)
    r = m - 1;
else
    l = m + 1;

以上就是简单的总结,其实分析一个问题能否用二分思想解决的时候,要注意的就是问题是否具有单调的性质,用白话来说,如果这个可以,那后边的都可以或者如果这个可以,那前边的都可以。这种二分很适合那些具有单调性质,验证答案很容易,但正面求解问题很难的情况

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值