二分搜索法的探究与心得

引言

在计算机科学中,二分搜索(Binary Search)算法是一种在有序数组中查找特定元素的基本搜索技术。其优点在于高效的搜索速度,时间复杂度为 ( O(log n) ),这一点与时间复杂度为O(n) 的线性搜索法相比,效率提高了数个数量级。二分搜索的核心思想是“分而治之”,即将大问题分解为小问题来逐步解决。

二分搜索适用场景

二分搜索不仅适用于简单的有序数组查找,它也适用于任何可以通过单调性质进行决策的问题,如实数范围内的最优解搜索、概率问题中的阈值确定,以及在计算机图形学中的光线追踪技术等。掌握二分搜索不仅能提升算法效率,也有助于培养分析和解决问题的思维能力。

二分搜索的两种主流写法

传统上,二分搜索有两种流行的写法:左闭右闭 [left, right] 和左闭右开 [left, right)。左闭右闭写法的循环条件为 while (left <= right),而左闭右开写法的循环条件为 while (left < right)。这两种写法虽然在实现上略有不同,但都广泛应用于实践中。

左闭右闭写法

在这种写法中,搜索范围包括 leftright 指向的元素。每次循环将区间分为三部分:小于 mid 的元素、等于 mid 的元素和大于 mid 的元素。根据与 target 的比较结果,我们可以排除其中的一个区间。当 leftright 相遇时,循环结束,此时 leftright 指向相同的可能是 target 的位置。

左闭右开写法

而在左闭右开的写法中,right 指向的元素不包含在搜索范围内。这种方法的结束条件是 leftright 相邻,此时 left 指向的是最后一个不符合条件的元素,right 指向的是第一个符合条件的元素。

left + 1 != right 写法的探讨

这种写法本质上是左闭右开的一种变体。其优势在于处理边界的清晰性和减少了在循环中对 mid 的过度检查。

写法原理

这种写法的基本原理是保持 leftright 指针之间至少有一个元素的间隔。这样,left 永远指向不满足条件的最后一个元素,而 right 指向的是满足条件的第一个元素。当 leftright 相邻时,即 left + 1 == right,它们之间的元素就是我们要找的元素。

二分搜索写法的具体问题优势

left + 1 != right 方法在处理特定类型的问题时显示出其优势,如“查找第一个大于等于目标值的元素”或“查找最后一个小于等于目标值的元素”。在这些问题中,通过维护一个明确的未满足条件和已满足条件的界限,left + 1 != right 写法减少了对边界的额外检查,从而提高了代码的执行效率和可读性。

对边界的处理

使用 left + 1 != right 的方法,边界处理变得直观而简单。在传统的左闭右闭写法中,我们需要小心翼翼地处理 leftright 的更新条件,以避免出现无限循环或者错过目标元素。而在 left + 1 != right 的方法中,我们避免了这种直接更新 leftrightmid 的操作,因此减少了对边界处理的担忧。

对区间的考量

left + 1 != right 的二分搜索中,对区间的考量显得尤为重要。这种写法天然地支持左闭右开的区间操作,即 [left, right)。在每次循环中,我们将区间从 mid 处分割,并根据比较结果决定是将 left 移动到 mid,还是将 right 移动到 mid。由于我们总是保持 leftright 之间至少有一个元素的距离,因此可以确保 mid 永远不会与 leftright 重合,这减少了循环中可能的逻辑错误。

这种方法的一个显著优点是它使得二分搜索的每一步都更加明确。在传统的左闭右闭方法中,当我们找到 mid 满足条件时,我们可能需要额外的逻辑来确定是返回 mid,还是继续在左边或右边的区间中搜索。而在 left + 1 != right 方法中,这种情况得到了简化:我们总是在确信没有遗漏任何可能的元素时才结束循环。

细节解析

1)迭代的过程

 整个二分的过程是一个不断迭代区间的过程,并且 红色游标 指向的元素始终是 红色 的;绿色游标 指向的元素始终是 绿色 的。迭代的过程就是不断向 红绿边界 逼近的过程。

2)结束条件

迭代结束时,红色游标 和 绿色游标 刚好指向 红绿边界,且区间长度为 2。

3)游标初始值

为什么 红色游标 初始值为 −1,绿色游标 初始值为 n ?

  能否将 红色游标 初始化为 0,绿色游标 初始化为 n−1 ? 答案是否定的,试想一下,如果数据元素都是绿色,红色游标 初始化为 0 就违背了 " 红色游标 指向的元素始终是 红色 的 " 这个条件;反之,如果元素都是红色的,也有类似问题。

4)中点位置

5)死循环

上面的程序模板是否会进入死循环?

  我们可以这么来看,当区间为 2 时,循环结束。当区间为 3 时,它一定可以变成区间为 2 的情况,当区间为4时,一定可以变成区间为 2 或者 3 的情况,也就是任何一种情况下,区间一定会减小,并且当等于 2 时,循环结束。所以不会造成死循环。

实践中的应用

在实际应用中,left + 1 != right 的方法尤其适合于寻找区间的极值问题,例如寻找旋转排序数组中的最小元素,或者在一个由两种元素(如“红色”和“绿色”)组成的数组中找到颜色变化的边界。在这些情况下,这种二分搜索方法能够清晰地定位到边界点,而不需要额外的边界检查。

代码模板

public int binarySearch(int[] nums, int target) {
    int left = -1, right = nums.length; // 初始化left为-1,right为数组长度

    while (left + 1 != right) { // 当左右指针相邻时停止
        int mid = left + ((right - left) >> 1); // 计算中点
        if (check()) { 
            left = mid; // 更新左(或右)指针
        } else { 
            right = mid; // 更新左指针
        }
    }
    // 循环结束时,left 为指向第一个绿色元素(或者 right 为指向最后一个红色元素)
    return left;
}

边界情况讨论

在数组的开始和结束位置,left + 1 != right 方法通过简化的逻辑清晰地处理了边界情况。尤其是在数组的结束位置,这种写法自然而然地避免了数组越界的风险,这是因为它始终保持 right 指针在数组范围内。

优势总结

left + 1 != right 的二分搜索法在多个方面展现出它的优势:

  • 精确的边界控制:通过保持 leftright 之间的间隔,这种方法减少了边界值的特殊处理,使得代码更加简洁。
  • 逻辑一致性:更新 leftright 变得一致和直观,不再需要额外的 if 判断来避免包含或排除中点值。
  • 减少错误:由于不需要处理 mid - 1mid + 1,此方法减少了由于错误更新索引而导致的无限循环或漏掉正确元素的风险。
  • 清晰的搜索意图:代码清晰地表达了搜索意图,特别是在区间分割的策略上,这对于阅读和维护代码的人来说是一个巨大的优势。
  • 可扩展性:这种写法易于扩展到更复杂的场景,如多维数组的二分搜索,或者需要进行复杂判断逻辑的问题。

与传统二分的对比

与传统的二分搜索方法相比,left + 1 != right 的写法在概念上更为简单和直观,尤其是对于边界条件的处理。在传统的二分搜索中,如果不小心处理,很容易在边界条件上出现错误,比如忘记了 mid - 1mid + 1,或者在 while 循环的条件中使用了错误的比较运算符。而在 left + 1 != right 的方法中,这些问题都不复存在。我们可以用一种更加一致和安全的方式来处理搜索逻辑。

结论

left + 1 != right 的二分搜索方法以其简洁的边界处理和清晰的逻辑流程,提供了一种新颖而有效的解决问题的方法。它不仅加强了对二分搜索的理解,还扩展了这一算法的应用范围,使得开发者能够更容易地实现和维护相关的算法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值