浅谈不同二分算法的查找情况

news2025/6/12 18:34:46

二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。

需要说明的是,以下二分算法都是基于有序序列为升序有序的情况,如果针对有序序列为降序的情况,二分的原理是相同的,将二分中用于check的条件表达式取反即可(小于变大于,小于等于变大于等于).

文章目录

  • 1. 模板1
  • 2.模板2
    • 2.1 边界死循环问题
  • 3. 总结

1. 模板1

    int search(vector<int>& nums, int target) {
        int l = 0,r = nums.size() - 1;
        while(l <= r)
        {
            int mid = (l + r) >> 1;
            if(nums[mid] == target) return mid;
            else if(nums[mid] > target) r = mid - 1;
            else l = mid + 1; 
        }
        return -1; 
    }

上述这种二分算法是较为常见的,可以用以查找某个数是否在一个序列中,如果在,就返回相应的下标;如果不在,就返回-1。

但是这种二分算法对于目标数有多个的情况,无法准确定位到位于左右边界的目标数,而且对于不存在目标数的序列,上述算法并不能找到第一个大于目标数或第一个小于目标数的下标。

2.模板2

为了解决第一类模板中无法解决的问题,第二类二分算法模板做出了改进。

对于序列中目标数存在多个的情况,这类模板实际提供两套模板,分别对应查找右边界和左边界。

    int find_left(vector<int>& nums,int target)
    {
        int l = 0,r = nums.size() - 1;
        while(l < r)
        {
            int mid = (l + r) >> 1;
            if(nums[mid] >= target)
                r = mid;
            else
                l = mid + 1;
        }
        return l;
    }
    int find_right(vector<int>& nums,int target)
    {
        int l = 0,r = nums.size() - 1;
        while(l < r)
        {
            int mid = (l + r + 1) >> 1;
            if(nums[mid] <= target)
                l = mid;
            else
                r = mid - 1;
        }
        return l;
    }

上述两种二分算法分别能够定位到位于左右边界的目标数,且能够处理好边界问题,而不陷入死循环。

而对于目标数不在序列中的情况,上述两种算法也能很好处理。对于左边界的情况,它会找到当前序列中最接近目标数的位置(在将目标数按照顺序插入原序列的情况下),且优先找大于目标数的位置,即优先找原序列第一个大于目标数的数;对于右边界的情况,它与左边界时的查找逻辑相同,唯一的区别在于它会优先找小于目标数的位置,即优先找原序列第一个小于目标数的数。

2.1 边界死循环问题

首先,我们要知道为什么二分算法会出现边界死循环问题。
对于整数范围中的二分算法,由于除法运算的向下取整特性,因此,当两个相邻的数相加再除以2后,总会得到这二者中较小的数,在特殊的情况下,会导致更新后,用于下一次二分的两边界与上一次相同,因此造成死循环。

在上述呈现的分别找左右边界的算法模板中,取中值mid时,有是否加上1的区别,这实际上也是为了处理边界死循环问题。

对于找左边界的情况,我们只考虑最后的临界情况,即左边界l与右边界r相邻的情况(因为只有在这种情况下,才可能出现边界死循环问题)。

lr指向的数不相同时:
如果要找到的下标是l,那么此时一定会执行r = mid这条语句,而mid == l,所以这种情况不会陷入死循环。
如果要找到的下标是r,那么此时一定会执行l = mid + 1这条语句,而mid == lr = mid + 1,因此也不会陷入死循环。

lr指向的数相同时:
由于是找左边界,所以一定会执行r = mid这条语句,所以最终也不会陷入死循环。

对于找右边界的情况,我们同样只考虑最后的临界情况,即lr相邻的情况。

lr指向的数不相同时:
如果要找的下标是l,由于mid = (l + r + 1) / 2,因此此时mid实际为r,那么此时一定会执行r = mid - 1这条语句,所以不会陷入死循环。

如果要找的下标是rmidr,因此实际会执行l = mid,也就是将l变为r,所以不会陷入死循环。

lr指向的数相同时:
由于是找右边界的情况,所以会执行l = mid 这条语句,而由于找右边界中,mid额外做了加1处理,所以mid == r,因此最终l就变为r,从而找到右边界,不会陷入死循环。

所以在找右边界中,对mid所做的加1处理,是很巧妙的处理——既解决了二分找右边界过程中会出现的死循环问题,又未破坏算法的整体逻辑。

3. 总结

综合来看,第二类二分算法模板适用范围更广,能很好地应对各种二分查找的情况,且不会出现边界死循环问题,因此第二类二分算法中的两个模板更推荐使用。

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

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

相关文章

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词

Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵&#xff0c;其中每行&#xff0c;每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid&#xff0c;其中有多少个 3 3 的 “幻方” 子矩阵&am…

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…

网络编程(UDP编程)

思维导图 UDP基础编程&#xff08;单播&#xff09; 1.流程图 服务器&#xff1a;短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…

Redis数据倾斜问题解决

Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中&#xff0c;部分节点存储的数据量或访问量远高于其他节点&#xff0c;导致这些节点负载过高&#xff0c;影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…

如何在最短时间内提升打ctf(web)的水平?

刚刚刷完2遍 bugku 的 web 题&#xff0c;前来答题。 每个人对刷题理解是不同&#xff0c;有的人是看了writeup就等于刷了&#xff0c;有的人是收藏了writeup就等于刷了&#xff0c;有的人是跟着writeup做了一遍就等于刷了&#xff0c;还有的人是独立思考做了一遍就等于刷了。…

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…