【刷题库】二分查找算法思想及模板

前言

假设有一个管道长为1000米,有一个未知的地方破了口,想要找出这个口,我们该怎么寻找?

在我们实际运用当中,很多地方都可以看到顺序排放的序列,比如按照价格递增的顺序排放,按照物体的大小进行依次排放,还有就是像上面的管道检查的问题等等…

如果需要查找某一个符合条件的值,依次查找就会花费很多不必要的查找,这时候使用二分就可以节约很大的成本。

面对上面1000米的管道,我们就可以采取二分机制,每次排除竟可能多的管道进行下一步查找。在这里插入图片描述

二分查找

为了更好的理解模板的查找过程,我们先举个简单的例子

在一个有序列表中,查找出54这个元素
在这里插入图片描述

第一轮

l = 0
r = 13
mid = (l + r) / 2 = 6

此时 mid 指向的数小于54,所以54在 mid 与 r 之间,可以排除l到 mid 的所有数据。
在这里插入图片描述

第二轮

l = mid + 1 = 7
r = 13(不变)
mid = (l + r) / 2 = 10

此时 mid 指向的数大于54,所以54在 l 与 mid 之间,可以排除 mid 到 r 的所有数据。

在这里插入图片描述

第三轮

l =  7(不变)
r = mid = 10
mid = (l + r) / 2 = 8

此时 mid 指向的数即是54,查找结束。

在这里插入图片描述

时间复杂度:O(logN)

空间复杂度:O(1)

这里的复杂度其实是平均复杂度,算法中的log级别的时间复杂度都是使用了分而治之的思想,这个底数是由分治的复杂度所决定的,也就是说,使用了二分机制查找,那它的底数就是2。

模板1

参照某位大佬的模板,我对次做了一些解释,方便学习

当我们将区间[l, r]划分成[l, mid][mid + 1, r]时,其更新操作是r = mid或者l = mid + 1;,计算mid时不需要加1。

代码模板

function search_1(l, r)
{
    
    
    while (l < r)
    {
    
    
        var mid = l + r >> 1;
        if(/*mid找到*/) return mid;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    return false;
}

在这里插入图片描述

  1. 为什么是 l < r 作为结束条件呢?

    解答:因为根据上面的图,如果还没有找到目标的话,左右指针就会重叠,一旦重叠就要退出了。

  2. 为什么使用l + r >> 1,还有其他方法吗?

    解答:在JavaScript中,可以通过 parseInt()Math.floor() 方法将小数向下取整,而 >> 是采用位移的方式,它看起来像个箭头,表示向右移一位,即除于2再取整,这时候就和 Math.floor((l + r) / 2) 效果相同。

模板2

当我们将区间[l, r]划分成[l, mid - 1][mid, r]时,其更新操作是r = mid - 1或者l = mid;,此时为了防止死循环,计算mid时需要加1。

function search_2(l, r)
{
    
    
    while (l < r)
    {
    
    
        var mid = l + r + 1 >> 1;
        if(/*mid找到*/) return mid;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return false;
}

运用

还是上面的数组,使用模板1查找54

var array = [1, 2, 4, 9, 11, 15, 20, 25, 54, 90, 100, 110, 111, 242];
function search_1(nums, target) {
    
    
    if (target == null || nums.length == 0) return false;

    var l = 0,
        r = nums.length - 1;
    while (l < r) {
    
    
        var mid = (l + r) >> 1;
        if(target == nums[mid]) return mid;
        if (target < nums[mid]) {
    
    
            r = mid;
        } else {
    
    
            l = mid + 1;
        }
    }
    return false;
}
function search_2(nums, target) {
    
    
    if (target == null || nums.length == 0) return false;

    var l = 0,
        r = nums.length - 1;
    while (l < r) {
    
    
        var mid = (l + r + 1) >> 1;
        if(target == nums[mid]) return mid;
        if(target > nums[mid]) l = mid;
        else r = mid - 1;
    }
    return false;
}

总结

二分查找要求数据是有序的。

  1. 中间位置与目标比较,相等则找到。否则,将原表拆分成两个表
  2. l > r 时,则未找到。

猜你喜欢

转载自blog.csdn.net/weixin_42339197/article/details/103911189
今日推荐