二分查找模板(y总版)

本文介绍了两种二分查找模板,版本一和版本二,分别适用于不同类型的区间划分策略。通过实例分析LeetCode题目,强调了check函数在选择边界时的重要性,并结合实际场景进行解释。适合理解和实践二分查找算法的开发者。

二分查找模板

首先先上模板,y总(B站大雪菜)总结出来了两套二分的代码,基本能解决九成左右的二分问题.二分在特别的边界问题上可以选用此模板作为参考。当然在一些简单的边界问题上,可以自己思考边界来自己写代码。

版本一

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

int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1; //除2 操作
        if (check(mid)) r = mid; //check函数即为边界的选择
        else l = mid + 1;
    }
    return l; //l r都可以,跳出while r = l
}

版本二

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

int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1; //注意+1操作
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

代码解释(来自B站大雪菜老师讲解,加些自己的理解)

在这里插入图片描述

如图我们把一个闭区间[l, r],分为左右两端(我们要明白,对于二分算法来说,数据在某种意义上是有序的,或者是直接有序,例如非递减。或者是以其他的形式有序,例如旋转有序。)再者,因为二分是抛弃一段,从另一段中继续寻找答案,所以我们就可以把整个过程一直当做是两段中选一段。其实分段的这个过程就是check()函数的确定。

① ① 对于模板一,我们就好比在查找图中绿色段中的左端点。如果我们的mid在红色段,肯定是不符合查找需求的,让l = mid + 1。如果mid是在绿色段,即符合我们的查找需求,但不是结束点,让r = mid
② ② 对于模板二,我们就好比在查找图中红色段中的右端点。如果我们的mid在绿色段,肯定是不符合查找需求的,让r = mid - 1。如果mid是在红色段,即符合我们的查找需求,但不是结束点,让l = mid。此时我们需要注意一点。即陷入死循环,举例:我们取下标l = r - 1,如果我们在计算时选择下取整(直接除2),m = (l + r) / 2 = (2 * l + 1) / 2 = l,我们再次更新l = mid,就陷入了死循环。

在这里插入图片描述

例题

LeetCode 69. x 的平方根

class Solution {
public:
    int mySqrt(int x) {
        int l = 0, r = x;
        while(l < r)
        {
            int mid = (long long)l + r + 1 >> 1;  //check函数 mid * mid <= x
            if(mid <= x / mid) l = mid;
            else r = mid - 1;

        }
        return l ;
    }
};

此时有读者按照上面的讲解,就在想,check函数能不能使用 mid * mid >= x。当然这种想法是没问题的。现学现用,但是我们来看这个题目的样例二,明显的给我们表明了,我们对于不能整数开平方的数来说,需要舍去小数,即下取整。当我们使用 mid * mid >= x 当x是整数的开平方数的话,自然是没有问题的,但当x不能被整开平方,我们的这个check最后取得结果就是上取整,不符合题意。
所以当我们在选择check条件的时候也不是随便两个模板换着用,一切以符合题意为主。

LeetCode 35. 搜索插入位置

这个题目就是简单的寻找有序数组中第一个大于等于target的位置,c++STL中有lower_bound()

return lower_bound(nums.begin(),nums.end(),target) - nums.begin();
class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        if(nums.empty() || nums.back() < target) return nums.size();
        int l = 0, r = nums.size() - 1;
        while(l < r)
        {
            int mid = (l + r) / 2;
            if(nums[mid] < target) l = mid + 1;
            else r = mid;
        
        }
        return l;
    }
};

这个题目就是边界选择,而且这个题目的check是可以改变的,画个图理解l, r的变化。

觉得文章有用,点个赞,点个收藏,支持一下

C++ 中常见的二分查找函数有 `lower_bound()`、`upper_bound()` 和 `binary_search()`,以下为你详细介绍: #### `lower_bound()` `lower_bound()` 函数返回一个迭代器,指向第一个不小于目标值的元素位置。其模板定义如下: ```cpp template<class ForwardIt, class T> ForwardIt lower_bound(ForwardIt first, ForwardIt last, const T& value); ``` 参数说明: - `first` 和 `last`:表示要搜索的有序序列的范围,`[first, last)` 是一个左闭右开区间。 - `value`:要查找的目标值。 示例代码: ```cpp #include <iostream> #include <algorithm> int main() { int a[8] = {1, 2, 4, 4, 5, 8, 10, 22}; int x = lower_bound(a, a + 8, 4) - a; std::cout << x << std::endl; return 0; } ``` #### `upper_bound()` `upper_bound()` 函数返回一个迭代器,指向第一个大于目标值的元素位置。其模板定义如下: ```cpp template<class ForwardIt, class T, class Compare> ForwardIt upper_bound(ForwardIt first, ForwardIt last, const T& value, Compare comp); ``` 示例代码: ```cpp #include <iostream> #include <algorithm> int main() { int a[8] = {1, 2, 4, 4, 5, 8, 10, 22}; int y = upper_bound(a, a + 8, 4) - a; std::cout << y << std::endl; return 0; } ``` #### `binary_search()` `binary_search()` 函数用于在数组(要求数组元素非递减,即要求升序)中以二分法检索的方式查找元素,若查找到 `value` 元素则返回 `true`,若查找不到则返回 `false`。示例代码如下: ```cpp #include <iostream> #include <algorithm> #include <vector> int main() { std::vector<int> a = { 4,10,11,30,69,70,96,100 }; bool is_found = binary_search(a.begin(), a.end(), 100); std::cout << is_found << std::endl; return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BiuPsYao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值