二分查找算法(指定数值的左右边界)

news2024/11/18 2:47:52

        之前一直以为二分查找有什么难的,不就是确定左右边界,然后while循环求mid,大于mid的找右半边,小于mid的找左半边。直到最后相同了就是最后查找的结果了.

        后来等真正用到二分查找算法的时候,发现问题远没有这么简单,上述的查找确实可以查找一个指定值x,但是x的具体位置,我们并不清楚.所以有一道题,就是给定一个数组,求出指定值x的左右边界,若没有返回-1,例如数组:

1 2 2 3 3 4

然后分别查询3,4,5.

预期结果应为

3 4
5 5
-1 -1

利用我们课堂上所讲的二分查找,根本无法解决这类问题,所以这里介绍一下二分算法的真正写法以及应用场景.(注:根据y总的方法所总结).

这里先放一个原题链接:

数的范围

这里直接给出二分查找的步骤,后面我会逐一讲解:

  1. 找一个区间[L,R],使得答案一定在该区间中
  2. 找一个判断条件,使得该判断条件具有二段性,并且答案(要查找的值)一定是该二段性的分界点
  3. 分析终点mid在该判断条件下是否成立,如果成立,考虑答案在哪个区间;若不成立,考虑答案在哪个区间(即我们平常写二分时所用的if else语句)
  4. 如果更新方式是right = mid,则对mid不用做任何处理;如果更新方式是left = mid,则需要在计算mid是加上1.(这句话不懂没关系,记住就行,后面也会给出解释.)

第一点,一般都是L=0,R=n-1,这个很好确定.

看下第2点,我们提到了二段性,先来讲一下什么是二段性:

简单来说,二段性是指把数组分成两段,一段里面是满足条件的,而另一段是不满足的.

例如1,2,2,3,3,4,5,6.

假设我们要查找的数字是3,那么我们只能这两种情况分:

不能是这样: 

这样大家就能理解什么是二段性了.

接下来看第2点中的“答案(要查找的值)一定是该二段性的分界点”,什么意思呢?

        我们假设此时要 求3的左边界,此时按照二段性,我们应该划分为上图的第二种情况,因为我们要找的答案一定是二段性中右侧的左端点,如下:

此时target的右侧一定是大于等于target的!

接下来看第三步,开始分析mid,更新边界.

假设mid在绿色部分(你不用结合数字分析,就理解为一种抽象的逻辑,mid是随便画的位置),如下:

此时若arr[mid] >= target,说明需要将right = mid(注意这一步,下面第四步要说),注意不能是mid-1,因为当前这个mid值可能就是结果,毕竟mid在target的右侧或者正好就是它自己.

假设mid在红色部分,如下:

相应的,此时arr[mid]一定是小于target的由于二段性,即arr[mid] < target. 所以此时target在右半部分,更新left = mid+1。这个时候为什么又要+1呢,这是由于mid最大才只可能在红色部分的最后一个,而由于二段性,mid一定不会是答案,所以left = mid+1.

这样第三步就完成了,紧接着看第四步:“如果更新方式是right = mid,则对mid不用做任何处理;如果更新方式是left = mid,则需要在计算mid是加上1.

就是看是left = mid 还是 right = mid,上面我们是在判断左边界时,是right = mid,所以我们在计算mid时,不需要对mid做任何处理,只需要正常操作即可,“mid = left + right >> 1”.

代码如下:

        int left = 0;
        int right = n-1;
        while(left < right)
        {
            int mid = left + right >> 1;
            if(nums[mid] >= k) right = mid;
            else left = mid+1;
        }

左边界求完了,接下来是求 右边界,按照步骤走:

第二步:找一个判断条件,使得该判断条件具有二段性,并且答案(要查找的值)一定是该二段性的分界点

上面说过了,这里也不再细说,这里一定是这种情况:

然后第三步,进行分析,然后更新边界.

此时target的左侧一定是小于等于target的!

mid在红色区域时:

此时arr[mid] <= target,需要更新left = mid,注意不能是left = mid+1,还是和上面判断左边界一个道理,因为当前mid可能就是结果(因为在有结果的这一侧),加上会导致错误!

mid在绿色区域

此时arr[mid]一定是大于target的,因为二段性,所以更新right = mid -1,这里-1 和上面所说的道理一模一样,mid最左只能在绿色的最左边,由于二段性,是不可能存在正确结果的,所以直接right=mid-1.

紧接着第四步,此时我们发现,判断右边界时,left=mid了,此时我们需要计算mid时处理一下,+1,即mid = left+right+1 >> 1.

代码如下:

            int left = 0;
            int right = n-1;
            while(left < right)
            {
                int mid = left + right + 1>> 1;
                if (nums[mid] <= k) left =mid;
                else right = mid -1 ;
            }

所以,题的全部代码为:

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int n,q;
    cin >> n >> q;
    vector<int> nums(n+1);
    for(int i = 0; i < n; i++)
    {
        cin >> nums[i];
    }
    while(q--)
    {
        int k = 0;
        cin >> k;
        int left = 0;
        int right = n-1;
        while(left < right)
        {
            int mid = left + right >> 1;
            if(nums[mid] >= k) right = mid;
            else left = mid+1;
        }
        if(nums[right] == k)
        {
            cout << right << " " ;
            right = n-1;
            while(left < right)
            {
                int mid = left + right + 1>> 1;
                if (nums[mid] <= k) left =mid;
                else right = mid -1 ;
            }
            cout << right << endl;
        }
        else
        {
            cout << -1 << " " << -1 << endl;
        }
        
    }
    return 0;
}

至此,二分查找的算法就讲解完毕了,现在是凌晨1点多,加之今天又复习了一天,写的可能有些省略了,如果你哪里不懂,欢迎评论区或者私信提问哦,最好是评论区,私信太多了,很大可能看不到,评论区一般都可以看到~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1363229.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【论文阅读笔记】ISINet: An Instance-Based Approach for Surgical Instrument Segmentation

1. 论文介绍 ISINet: An Instance-Based Approach for Surgical Instrument Segmentation ISINet&#xff1a;一种基于实例的手术器械分割方法 2020 MICCAI 【Paper】 【Code】 2.摘要 我们研究了机器人辅助手术场景中手术器械的语义分割任务。我们提出了基于实例的手术器械…

计算机Java项目|基于Springboot实现患者管理系统

作者主页&#xff1a;编程指南针 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、掘金特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容&#xff1a;Java项目、毕业设计、简历模板、学习资料、面试题库、技术互助 文末获取源码 项目编号&#xff1a;KS-032…

Hello 2024

Hello 2024 A. Wallet Exchange 题意&#xff1a;Alice和Bob各有a和b枚硬币&#xff0c;每次他们可以选择交换硬币或者保留&#xff0c;然后扣除当前一枚手中的硬币&#xff0c;当一方没得扣另一方就赢了。 思路&#xff1a;Alice先手&#xff0c;所以当硬币和为奇数时Alice…

Java面试之并发篇(一)

1、前言 本篇主要总结JAVA面试中关于并发相关的高频面试题。本篇的面试题基于网络整理&#xff0c;和自己编辑。在不断的完善补充哦。 2、简述程序、进程、线程、的基本概念&#xff1f; 2.1、程序 程序&#xff0c;是含有指令和数据的文件&#xff0c;被存储在磁盘或其他的…

基于神经网络的手写汉字提取与书写评分系统研究

相关源码和文档获取请私聊QQ:3106089953 论文目录结构 目 录 摘 要 I Abstract II 目 录 IV 第1章 绪论 1 1.1. 研究背景与意义 1 1.2. 国内外研究现状 2 1.2.1. 文本定位技术研究现状 2 1.2.2. 手写汉字识别研究现状 3 1.2.3. 汉字书写质量评价方法研究现状 4 1.3. 本文所做工…

OS_lab——bochs源码的编译与安装

1. 实验环境VMware station 15 Ubuntu 14.04.6 32位。2. 实验步骤2.1 安装虚拟机&#xff0c;并在虚拟机根目录下编译并安装bochs环境。 2.2 使用bochs自带工具bximage创建虚拟软驱。 2.3 编写引导程序boot.asm并用nasm编译得到引导文件boot.bin和boot.com。 2.4 修改bochs…

Hadoop分布式文件系统(二)

目录 一、Hadoop 1、文件系统 1.1、文件系统定义 1.2、传统常见的文件系统 1.3、文件系统中的重要概念 1.4、海量数据存储遇到的问题 1.5、分布式存储系统的核心属性及功能含义 2、HDFS 2.1、HDFS简介 2.2、HDFS设计目标 2.3、HDFS应用场景 2.4、HDFS重要特性 2.4…

性能分析与调优: Linux 安装基于BPF的bcc-tools系统性能工具库

目录 一、实验 1.环境 2.agent服务器安装使用ELRepo安装依赖包 3.agent服务器安装基于BPF的bcc-tools系统性能工具库 二、问题 1.安装bcc-tools后执行命令报错 一、实验 1.环境 &#xff08;1&#xff09;主机 表1-1 主机 主机架构组件IP备注prometheus 监测 系统 pro…

【C++】- 类和对象(!!C++类基本概念!this指针详解)

类和对象 引入类类的定义类的访问限定操作符类的作用域类的实例化类对象模型this指针 引入类 在 C中&#xff0c;引入了一个新的定义----------类。类是一种用户自定义的数据类型&#xff0c;用于封装数据和行为。类可以看作是一个模板或蓝图&#xff0c;描述了一组相关的数据和…

JVM虚拟机的垃圾回收器(面试题)

1.什么是垃圾回收 垃圾回收主要说的是java会自动把程序在运行过程中产生的一些没有用的对象给回收掉&#xff0c;这样可以避免内存的浪费。 java主要是通过一个叫“根可达”的算法来识别这个对象是否可以被回收的&#xff0c;然后回收的算法也主要有三种&#xff1a;标记清除&a…

QT c++和qml交互实例

文章目录 一、demo效果图二、c和qml交互的基本方式1、qml访问C类对象 三、关键代码1、工程结构图2、c代码MainWindow.cppMainQuickView.cppStudentInfoView.cppStudentInfoModel.cpp 3、qml代码main.qmlMainQuickTopRect.qmlMainQuickMiddleRect.qmlMainQuickMiddleTableRect.q…

服务器cpu占用很高如何排查问题

前段时间&#xff0c;运维监控发现有个项目cpu占用很高&#xff0c;并且还在持续不断增长&#xff0c;服务不能正常响应&#xff0c;如下图&#xff1a; 在服务器上面安装了arthas&#xff0c;下载地址&#xff1a; https://alibaba.github.io/arthas/arthas-boot.jar 我使用了…

Linux stm32串口下载程序

一、工具 使用stm32flash进行串口下载 二、stm32flash安装 sudo apt-get install stm32flash 三、查看串口设备名称 先拔掉串口运行下面指令&#xff0c;获得所有设备名称,插上串口再运行一次&#xff0c;新增的就是串口设备名称&#xff0c;记住串口设备名称&#xff0c;以…

【信息论与编码】习题-判断题-第一部分

目录 判断题1. 对于N个对立并联信道&#xff0c;其信道容量CN2. 汉明码是一种线性分组码。3. 某一信源&#xff0c;不管它是否输出符号&#xff0c;只要这些符号具有某些概率特性&#xff0c;就有信息量。4. 若检错码的最小距离为dmin&#xff0c;则可以检测出任意小于等于dmin…

集团企业OA办公协同平台建设方案

一、企业对协同应用的需求分析 实现OA最核心、最基础的应用 业务流转&#xff1a;收/发文、汇报、合同等各种审批事项的业务协作与办理 信息共享&#xff1a;规章制度、业务资料、共享信息资源集中存储、统一管理 沟通管理&#xff1a;电子邮件、手机短信、通讯录、会议协作等…

期货日数据维护与使用_日数据维护_日数据更新

目录 写在前面&#xff1a; 下载日数据 下载“新增合约”日数据 下载“待更新合约”日数据 日数据文件 “选择日数据所在目录”按钮点击 “执行”按钮点击 sqlite3代码 按钮点击后执行的代码 子线程代码 写在前面&#xff1a; 本文默认已经创建了项目&#xff0c;如…

Archlinux下自启动rclone mount

路径&#xff1a; /etc/systemd/system/rclonemount.service [Unit] Descriptionrclonemount Requiresnetwork-online.target.wants Afteralist.service[Service] Typesimple ExecStartPre/bin/mkdir -p /media ExecStart/usr/bin/rclone mount \aliyun: /media \--config /ro…

Docker学习与应用(五)-DockerFile

1、DockerFile 1&#xff09;DockerFile介绍 dockerfile是用来构建docker镜像的文件&#xff01;命令参数脚本&#xff01; 构建步骤&#xff1a; 1. 编写一个dockerfile文件 2. docker build 构建称为一个镜像 3. docker run运行镜像 4. docker push发布镜像&#xff08;D…

2024最新前端源码分享(附效果图及在线演示)

分享10款非常有趣的前端特效源码 其中包含css动画特效、js原生特效、svg特效以及小游戏等 下面我会给出特效样式图或演示效果图 但你也可以点击在线预览查看源码的最终展示效果及下载源码资源 粒子文字动画特效 基于canvas实现的粒子文字动画特效 会来回切换设定的文字特效 图…

Docker学习与应用(四)-容器数据卷

1、容器数据卷 1&#xff09;什么是容器数据卷 docker的理念回顾 将应用和环境打包成一个镜像&#xff01; 数据&#xff1f;如果数据都在容器中&#xff0c;那么我们容器删除&#xff0c;数据就会丢失&#xff01;需求&#xff1a;数据可以持久化 MySQL&#xff0c;容器删…