算法基础之二分查找

news2024/11/16 1:20:11

原题链接

一 、二分查找中的mid+1和mid-1的问题

二分查找中的边界问题处理不好很容易导致死循环和计算错误的问题,以题目 数的范围为例。

  • 题目大意

​ 二分查找重复数第一次出现的位置和最后一次出现的位置。

  • 数学含义

​ 第一次位置即 找到 一个长度最大的 >=X 区间的 左边界

​ 最后一次位置即 找到一个长度最大的 >= X 区间的右边界

注意 找的目标是左边界或者右边界 不是找整个区间

  • 图形示意

    L=左边界 R=有边界 M=中间值(所选比较的数)T=目标位置

    M的意义在于通过缩小区间 找到位置T

image-20230905221643547

  • 重要结论

    重要的一步是将M的值传递出去时候,即 L=M 或者R = M,即把目标范围的左或右边界设置为M。

    因为不管是M+1或者是M-1 ,指针都会移动。直接赋值M的时候,指针可能不会移动,就会造成死循环。

二、具体代码分析

找第一次出现的位置

  • 循环结束的条件 L==R,最后一次循环时 L+1==R,即搜索的目标范围内有两个元素。
  • M 为L+R的下取整,有可能取到L,不可能取到R,但是赋值是赋给R,即R=L,最终条件 L==R 会结束循环。
int l = 0, r = n - 1;
while (l < r) {
    int mid = l + r >> 1;
    if (a[mid] < x)  l = mid + 1;
    else    r = mid;
}

找最后一次出现的位置

  • 方法一 以【0,n-1】闭区间,最小搜索范围是2个元素,取右边界

    因为M的值是赋给L的,即L=M,所以M不能取到左边界,所以要向上取整。

所谓的闭区间 ,个人理解最后一次循环时只有两个元素,左右指针在这两个数之间移动。

image-20230905224331820

int l = 0, r = n - 1;
while (l < r) {
    int mid = l + r + 1 >> 1;
    if (a[mid] <= x)  l = mid;
    else    r = mid-1;
}
  • 方法二 以【0,n) 左闭右开区间 ,最小搜索范围是3个元素,取中间元素

    所谓左闭右开区间,个人理解需要加上循环上的判断控制,才能形成开区间效果,使得最后一次循环时只有三个元素,左右指针在第一、第二个数直接移动。

    由于l +1 < r 保证了最小搜索范围是3个元素,所以 l + r >> 1 时M会取到L和R中间的数,不会取L或者R,主要保证不能取到L。

    image-20230905225702420

int l = 0, r = n ;
while (l +1 < r) {
    int mid = l + r  >> 1;
    if (a[mid] <= x)  l = mid;
    else    r = mid; // 想想此处可不可以写成 r=mid-1
}

第一次位置 左闭区间0开始

int l = 0, r = n - 1;
while (l < r) {
    int mid = l + r >> 1;
    if (a[mid] < x)  l = mid + 1;
    else    r = mid;
}
  • 方法三 以(-1,n)左开右开区间

左开是为了求第一次出现位置,同样保证最后一次循环是3个元素, l + r >> 1 时M会取到L和R中间的数,不会取L或者R,主要保证不能取到R,因为找第一次位置主要是将M赋值给R。

第一次位置

int l = -1, r = n - 1;
while (l+1 < r) {
    int mid = l + r >> 1;
    if (a[mid] < x)  l = mid ;
    else    r = mid;
}

最后一次位置

while (l+1 < r) {
    int mid = l + r >> 1;
    if (a[mid] <= x)  l = mid ;
    else    r = mid;
}

完整代码

需要注意最后输出

第一次坐标 的二分的边界定为 左边为=X 则所求为R

最后一次坐标的二分边界定位 左边为<=X 右边>X 则所求为L

#include<iostream>
using namespace std;
const int N=1e5+5;
int n,m,q[N];
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=0;i<n;i++) scanf("%d",&q[i]);
    while(m--)
    {
        int k;scanf("%d",&k);
        //寻找第一个等于K的坐标 我这边让二分的边界定为 左边为<5 右边>=5 则所求为r
        int l=-1,r=n;
        while(l+1<r)//当l与r没有相接的时候,求边界
        {
            int mid=l+r>>1;
            //下面找第一个>=5的坐标
            if(q[mid]>=k) r=mid;
            else l=mid;
        }
        //此时得到的r是第一个>=5的坐标
        if(q[r]!=k) {
            printf("-1 -1\n");
                        continue;

        }
        int ll = r,rr = n;
       while(ll+1<rr)
        {

            int mid=ll+rr>>1;
            if(q[mid]<=k) ll=mid;
            else rr=mid;
        }
       printf("%d %d\n", r, ll);

    }

}

三、个人心得体会

开区间 其实就是 最小搜索范围是3元素+左右新增点 的方式。这样就避免了L=M或者R=M 的死循环问题。

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

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

相关文章

[代码解读] A ConvNet for the 2020s

代码地址&#xff1a;https://github.com/facebookresearch/ConvNeXt ConvNeXt/models/convnext.py整体的代码结构如下&#xff1a; 接下来我们一部分一部分来看。 1.Block类&#xff1a; class Block(nn.Module):r""" ConvNeXt Block. There are two equiva…

Redis集群架构搭建——主从、哨兵、集群

上一篇文章Ubuntu上通过源码方式安装Redis已经介绍了如何安装redis&#xff0c;在这篇文章中&#xff0c;将会教大家搭建Redis的几种高可用的架构&#xff1a;主从架构、哨兵集群、Cluster集群。 本篇文章使用的redis版本为6.2.13&#xff0c;不同版本的配置可能有略微的区别&a…

C++:list

目录 List的模拟实现 List节点类 List链表结构 List迭代器类 结构 T& operator*(); T& operator->(); Self& operator(); Self operator(int); Self& operator--(); Self& operator--(int); bool operator!(const Self& l); bool oper…

JDK、JRE 和 JVM 的区别和联系

三者关系 就这三者的关系而言&#xff0c;jvm是jre的子集&#xff0c;jre是jdk的子集&#xff0c;具体关系如下图&#xff1a; Java的执行流程 对于一个Java程序&#xff0c;其执行流程大致如下&#xff1a; 开发人员使用JDK编写和编译Java源代码&#xff0c;生成Java字节码文…

二叉树层序遍历及判断完全二叉树

个人主页:Lei宝啊 愿所有美好如期而遇 目录 二叉树层序遍历&#xff1a; 判断完全二叉树&#xff1a; 二叉树层序遍历&#xff1a; 层序遍历就是一层一层&#xff0c;从上到下遍历&#xff0c;上图遍历结果为&#xff1a;4 2 7 1 3 6 9 思路&#xff1a; 通过队列来实现层序…

lenovo联想笔记本电脑ThinkPad X13 AMD Gen2(20XH,20XJ)原装出厂Windows10系统镜像

联想原厂Win10系统&#xff0c;自带所有驱动、出厂主题壁纸、系统属性联想LOGO专属标志、Office办公软件、联想电脑管家等预装程序 链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;dolg 适用于型号&#xff1a;20XL,20XJ,20XG,21A1,20XK,20XH,20XF,21A0 所需要…

1.vue3脚手架在vscode下面建立

一、下载安装node.js Node.js (nodejs.org) 二、安装vue3脚手架 #添加项目脚手架 npm install -g vue/cli 三、建立项目 #项目建立 vue create {appname} 测试项目安装成功&#xff1a;运行npm run serve命令 npm run serve 证明脚手架、项目环境已配置好 四、添加配件&#x…

5+非肿瘤+铁死亡+实验验证生信思路解析

今天给同学们分享一篇非肿瘤铁死亡实验验证的生信文章“Identification and validation of ferroptosis-related gene signature in intervertebral disc degeneration”&#xff0c;这篇文章于2023年2月6日发表在Front Endocrinol (Lausanne)期刊上&#xff0c;影响因子为5.2。…

Windows专业版的Docker下载、安装与启用Kubenetes、访问Kubernetes Dashboard

到Docker 官网https://www.docker.com/ 下载windows操作系统对应的docker软件安装 Docker Desktop Installer-Win.exe 2023-09版本是4.23 下载后双击安装 重启windows后&#xff0c;继续安装 接受服务继续安装 解决碰到的Docker Engine stopped 打开 控制面板》程序》启用或关…

Java-day15(Java常用类)

Java常用类 1.String类 public class test1 {/** String&#xff1a;代表不可变的字符序列&#xff0c;底层使用char[]存放* String是final的 * */Testpublic void test() {String str1 "Java EE";String str2 "Java EE";String str3 new String("…

用sublime测试正则表达式

1 打开sublime 2.使用ctrlf快捷键 3.开启如下功能 4.测试

什么是语法糖?Java中有哪些语法糖?

什么是语法糖&#xff1f;Java中有哪些语法糖&#xff1f; 语法糖 语法糖&#xff08;Syntactic Sugar&#xff09;&#xff0c;也称糖衣语法&#xff0c;是由英国计算机学家 Peter.J.Landin 发明的一个术语&#xff0c;指在计算机语言中添加的某种语法&#xff0c;这种语法对…

【操作系统笔记十三】Shell脚本编程

什么是 shell shell 就是命令解释器&#xff0c;用于解释用户对操作系统的操作&#xff0c;比如当我们在终端上执行 ls &#xff0c;然后回车&#xff0c;这个时候会由 shell 来解释这个命令&#xff0c;并且执行解释后的命令&#xff0c;进而对操作系统进行操作。 在 Centos…

初识软件工程

软件工程是一门涵盖软件开发、维护和管理的学科&#xff0c;它通过应用工程化的原则和方法来提高软件系统的质量和可靠性。在当今数字化和信息化的时代&#xff0c;软件工程对于现代社会的各个领域都具有至关重要的作用。 基本概念&#xff1f; 计算机系统中与硬件相互依存的一…

【力扣】300. 最长递增子序列 <动态规划>

【力扣】300. 最长递增子序列 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 [0,3,1,6,2,2…

Wiki.js - 下一代的开源Wiki软件

简介&#xff1a;在众多开源的Wiki软件中&#xff0c;Wiki.js无疑是一个独特且现代的选择。基于Node.js构建&#xff0c;使用了最新的Web技术&#xff0c;Wiki.js为用户提供了一个美观且功能丰富的界面&#xff0c;同时还保留了强大的扩展性和自定义性。无论你是为个人、团队或…

一文掌握CodiMD安装与使用

简介&#xff1a;CodiMD 是一个基于 Markdown 语言的实时协作文档编辑器&#xff0c;它允许多个用户在同一个文档上进行实时编辑。CodiMD 的前身是 HackMD&#xff0c;但为了满足更开放的开源社区需求&#xff0c;CodiMD 作为其社区版本独立出来。 优势&#xff1a; 1. 开源且…

9+单细胞+实验验证,探讨单基因对癌细胞转移作用的思路方向

今天给同学们分享一篇单细胞实验的生信文章“Identification of RAC1 in promoting brain metastasis of lung adenocarcinoma using single-cell transcriptome sequencing”&#xff0c;这篇文章于2023年5月18日发表在Cell Death Dis期刊上&#xff0c;影响因子为9。 本研究旨…

2023研究生数学建模E题保姆级思路 出血性脑卒中临床智能诊疗

本次E题是一道J机器学习题目&#xff0c;难度也比较高&#xff0c;该题一般是有正确结果的&#xff0c;容易踩坑&#xff0c;不太建议小白选择&#xff0c;小白可以选择D题&#xff0c;D题思路也可以看另一篇文章&#xff0c;总的难度都不算低&#xff0c;这三道的难度接近&…

科目三基础四项(一)

​ 第一天&#xff0c;基础操作&#xff0c;仪表&#xff0c;方向&#xff0c;挡位 按照模块来 1、方向盘两手在两侧 ​ 编辑 转向时的角度&#xff0c;只用&#xff1a;向左540&#xff0c;向右180 向左打和向右打的角度要抵消&#xff0c;回正 掉头向左打满再回 注意…