首页 > 编程语言 >二分查找算法详讲(三种版本写法)原创

二分查找算法详讲(三种版本写法)原创

时间:2024-05-28 23:55:13浏览次数:14  
标签:二分 详讲 下标 idx int mid while 查找 写法

介绍:

二分查找算法(Binary Search)是一种在有序数组中查找目标元素的算法。
它的基本思想是通过将目标元素与数组的中间元素进行比较,从而将搜索范围缩小一半。

  • 如果目标元素等于中间元素,则搜索结束;
  • 如果目标元素小于中间元素,则继续在左半部分查找;
  • 如果目标元素大于中间元素,则在右半部分查找。

通过不断地将搜索范围缩小一半,最终可以找到目标元素或确定目标元素不存在。

接下来通过例题介绍二分的不同写法

例题:

输入一个整数 n, 接下来一行输入 n 个整数(保证整数序列有序), 最后输入一个整数 m, 查找 m 在序列中的起始下标和结束下标

示例1:

输入:

5
1 2 2 4 5
2

输出:

1 2

解释:

2 在序列中的起始和结束位置是下标 1 和 2

代码讲解:

二分代码按照退出条件分为

  1. while (l <= r)
  2. while (l < r)

代码中的所有 lr 都是序列的左右闭区间

代码中的所有 l + r >> 1l + r + 1 >> 1 分别相当于 (l + r) / 2(l + r + 1) / 2>>是按位右移, 整数向右位移一位相当于除2

代码中的所有 x, 都是目标值, 也就是要查找的值; 所有的 idx, 是答案, 也就是要查找数的起始下标或结束下标

先讲第一种: while (l <= r), 在l > r时退出

// 查找起始下标
int l = 0, r = n - 1, idx = 0;
while (l <= r)
{
    int mid = l + r >> 1;  // 一分为3, [l, mid), [mid, mid], (mid, r]
    if (a[mid] < x) l = mid + 1;  // 如果当前中间值比 x 小, 需要去序列的右区间, 因为mid位置的数比 x 小, 那么左边的区间(l, mid]的所有数都比 x 小
    else if (a[mid] > x) r = mid - 1;  // 同上
    else if (a[mid] == x)  // 等于答案时
    {
        idx = mid;
        r = mid - 1;  // 我们要找的时起始的下标, 虽然此时a[mid] == x, 但是mid的左边可能还有等于x的值, 所以我们要继续往左区间去找
    }
}

// 查找结束下标(代码中只有注释的地方和上面的代码不一样)
int l = 0, r = n - 1, idx = 0;
while (l <= r)
{
    int mid = l + r >> 1;  // 一分为3, [l, mid), [mid, mid], (mid, r]
    if (a[mid] < x) l = mid + 1;  
    else if (a[mid] > x) r = mid - 1;  
    else if (a[mid] == x)  
    {
        idx = mid;
        l = mid + 1;  // 我们要找的时结束的下标, 虽然此时a[mid] == x, 但是mid的右边可能还有等于x的值, 所以我们要继续往右区间去找
    }
}

观察上面代码我们可以把a[mid] == x的情况跟其他两种情况合并

// 查找起始下标
int l = 0, r = n - 1, idx = 0;
while (l <= r)
{
    int mid = l + r >> 1;  // 一分为3, [l, mid), [mid, mid], (mid, r]
    if (a[mid] < x) l = mid + 1;  
    else if (a[mid] >= x)
    {
         idx = mid;
         r = mid - 1;  // 继续往左区间找
    }
}

// 查找结束下标
int l = 0, r = n - 1, idx = 0;
while (l <= r)
{
    int mid = l + r >> 1;
    if (a[mid] <= x)
    {
        idx = mid;
        l = mid + 1;  // 继续往右区间找
    }
    else if (a[mid] > x) r = mid - 1;
}

下面讲第二种: while (l < r) 在l == r时退出

大家可以发现这种写法不需要 idx 这个变量来记录最终查找的x的起始下标或结束下标了, 因为最后l就是对应的起始下标或结束下标。(r等于l, 所以用r也行)

查找起始下标
int l = 0, r = n - 1;
while (l < r)
{
    int mid = l + r >> 1;  // 区间分成了两个 [l, mid] 和 (mid, r]
    if (a[mid] < x) l = mid + 1;

    // 当a[mid] == x的时候, r一直往左, 所以当有多个相同的x的话, 会查找到第一个
    else if (a[mid] >= x) r = mid;  // 因为a[mid]可能 == x, 因为mid也可能满足条件, 所以区间变成[l, mid]
}

查找结束下标
int l = 0, r = n - 1, idx = 0;
while (l < r)
{
    int mid = l + r + 1 >> 1;  // 区间分成了两个 [l, mid) 和 [mid, r]
    if (a[mid] > x) r = mid - 1;

    // 当a[mid] == x的时候, l一直往右, 所以当有多个相同的x的话, 会查找到最后一个
    else if (a[mid] <= x) l = mid;  // 因为a[mid]可能 == x, 因为mid也可能满足条件, 所以区间变成[mid, r]
}

接下来讲一下第二种查找结束下标的时候 为什么是 mid = l + r + 1 >> 1,而不是 mid = l + r >> 1;
c++默认向0取整, 对于正整数你可以说是向下取整, 也就是 5 / 2 = 2,
当出现 l = r - 1 的时候, 此时 mid = (l + r) / 2 向下取整后等于 r - 1 , 如果此时进入了a[mid] <= x的分支, 那么 l = mid = r - 1, 这时会发现 l 没有发生变化, 那么就会一直陷入死循环

先更到这里, 后面再补充

觉得写的不错的话, 点个赞吧

标签:二分,详讲,下标,idx,int,mid,while,查找,写法
From: https://www.cnblogs.com/xxctx/p/18219283

相关文章

  • 【C++】<图形库> 三人成棋(面向对象写法)
     目录一、游戏需求二、程序架构三、代码实现四、实现效果五、已知BUG一、游戏需求构建一个五子棋游戏,在自定义棋盘宽度和高度的基础上,实现三人对战功能,并且能判定谁输谁赢。二、程序架构(1)对象分析:【1】需要一个棋盘(ChessBoard)类来绘制棋盘。【2】有三人对......
  • 回顾二分答案 例题分析(D. Fast and Fat 和 I.Path Planning)
    对于二分答案的引述来自:二分查找&二分答案万字详解,超多例题,带你学透二分。_c++二分答案怎么确定是l<r还是l<=r-CSDN博客概念:二分答案:答案有一个区间,在这个区间中二分,直到找到最优答案。什么时候用二分答案?答案属于一个区间,当这个区间很大时,暴力超时。但重要的是——这......
  • WPF在ListView中绑定Command命令的写法
    假定:ViewModel中有一个数据源叫Persons,有一个命令叫DoCommand,通过System.Windows.Interactivity触发器绑定鼠标MouseUp事件,当UI端绑定了DataContext数据上下文之后,Command="{BindingDoCommand}"是找不到这个命令的,必须使用Binging类的RelativeSource属性先找到当前UI,再找到DataC......
  • 准备电赛——CCSMSP430F5529标准库——定时器定时多少秒以及定时中断的写法
    中断向量TIMERx_A0_VECTOR是CCR0的中断向量    (第一个引脚)TIMERx_A1_VECTOR是TAIV的中断向量#defineTIMER2_A1_VECTOR(43*1u)/*0xFFD6Timer2_A5CC1-4,TA*/#defineTIMER2_A0_VECTOR(44*1u)......
  • 整数二分查找的实现
    引入        在一个有序数组中,如果我们想查找某一元素,朴素做法就是从前往后枚举,时间复杂度会达到。但是因为此数组是有序的,所以就可以通过这个性质,使用二分查找实现,可以使时间复杂度降到。        下面我们就来讲整数二分查找的实现。定义        ......
  • 算法刷题笔记 数的范围(C++实现)(二分法重要例题)
    文章目录题目描述题目思路题目代码(C++)题目感想题目描述给定一个按照升序排列的长度为n的整数数组,以及q个查询。对于每个查询,返回一个元素k的起始位置和终止位置(位置从0开始计数)。如果数组中不存在该元素,则返回-1-1。输入格式:第一行包含整数n和q,表示数组长度和询......
  • 易语言关于微信收款监控软件写法的思考
    想写微信收款监控,正规途径是企业认证申请sdk。可是这个确实是有门槛的,好像每年都要交不少的钱,好像是,具体我也不记得了。如果能够监控收款,就可以利用微信写自动成交工具。很多卖虚拟的,就可以实现自动发卡。所以很多人就想走其他的捷径,看能不能绕过官方,自己监控。最简单的......
  • 二分查找法-I
    描述请实现无重复数字的升序数组的二分查找给定一个元素升序的、无重复数字的整型数组nums 和一个目标值target ,写一个函数搜索nums 中的target,如果目标值存在返回下标(下标从0开始),否则返回-1数据范围:0≤len(nums)≤2×1050≤len(nums)≤2×105, 数组中任意值......
  • 机场大巴(二分查找与二分答案)
    题目描述一场神秘大会要在小明的家里举办了!他的处于世界各地的客人将会到达当地的机场,前来参会。具体地说,有N个客人到达了机场(1≤N≤100000),其中客人i在时间ti(0≤ti≤10^9)到达。小明安排了M(1≤M≤10^5)辆大巴来机场接这些客人。每辆大巴可以乘坐C个客人(1≤C≤N)。小明正在......
  • 1-数组-11-二分查找-LeetCode704
    1-数组-11-二分查找-LeetCode704参考:代码随想录LeetCode:题目序号35更多内容欢迎关注我(持续更新中,欢迎Star✨)Github:CodeZeng1998/Java-Developer-Work-Note技术公众号:CodeZeng1998(纯纯技术文)生活公众号:好锅(Lifeismorethancode)博客园:CodeZeng1998其他平台:CodeZeng19......