【算法笔记】二分查找 红蓝染色法

目录

  • 二分查找 红蓝染色法(感谢灵神)
    • 闭区间[left, right]
    • 左闭右开区间[left, right)
    • 开区间(left, right)
    • 变式

二分查找 红蓝染色法(感谢灵神)

这里是灵神的教学视频:二分查找 红蓝染色法_哔哩哔哩_ bilibili

学了二分查找之后其实一直不是很理解,直到昨天看了灵神的讲解,有了全新的理解,有一种直冲天灵盖的感觉,写个笔记整理一下,感谢灵神

对于一个有序数组,我们如果想查找其中的某一个元素,我们可以通过从头遍历其中的所有元素,如果有匹配的元素,则返回元素的值,但是这种暴力解法不但没有利用有序数组这个特点,而且时间复杂度是O(n),不是很有效率。

这个时候我们可以采用二分查找的方式:每次排除一半的元素,这样我们每查找一个元素的时候,他的时间复杂度就是O(logn),要比暴力解法好很多。

二分查找中我们会涉及到一些变量,以及他们在每一轮循环中的变化情况:左右游标left、right,中间游标mid,以及我们要找的值target,其中左右游标用于在每次循环中缩小我们的查找区间确定区间外数值的大小,mid游标用于与target值进行比较,辅助左右游标的具体移动情况。

闭区间[left, right]

下面我们介绍在闭区间[left, right]内查找的情况:

  1. 我们将left游标初始化为数组的起始下标0right初始化为数组末尾的下标arr.length-1,mid指向左右游标的中间值left+(right - left)/2,这样我们每次就可以排除一半的数据,是最优解。

    left+(right - left)/2这里为什么这样写,是因为防止在Java中直接进行left+right导致整型数字太大导致越界的情况

  2. 我们将 < t a r g e t < target <target的元素标记为红色, ≥ t a r g e t \geq target target的元素标记为蓝色,但是我们要清楚,区间内的元素我们是不知道它们的颜色的,这点很重要!!假定我们现在要查找的数组为:[5,7,7,8,8,10],target值为8,游标的位置如下图:

    在这里插入图片描述

  3. 经过比较之后,我们发现mid指向的值为7,满足 < t a r g e t < target <target的条件,那么我们将left更新为mid+1,原有的元素变为如下的颜色:

    在这里插入图片描述

    这里为什么不更新为mid??

    这也是我一直不太清楚的一个点,现在我来试着说一下:因为我们选择的方式是在闭区间[left, right]内查找,所以我们要保证被比较过的元素在区间外面,没有比较过的元素在区间内部,而mid是我们比较的最后一个元素,那么我们只需要将游标更新为mid+1或者是mid-1就可以保证区间内的元素都是未经比较的,并且区间外的元素都是已经确定颜色的

  4. 继续进行比较,mid指向的值为8满足 ≥ t a r g e t \geq target target的条件,此时我们不确定的区间也就是[left, mid-1],所以我们更新右游标到mid-1的位置,保证区间外的元素都已经确定过:

    在这里插入图片描述

  5. 继续进行比较,mid指向8,满足 ≥ t a r g e t \geq target target条件,再次更新右游标到mid-1的位置:

    在这里插入图片描述

  6. 到这个时候我们发现:整个数组已经全部染色,也就意味着我们确定了所有元素和目标元素的大小关系,我们要清楚一个关键点:right+1指向的元素一定是蓝色( ≥ t a r g e t \geq target target),left-1指向的元素一定是红色( < t a r g e t <target <target,每次循环的过程中这个是不会变的,为了方便记忆灵神给这个关键点取名叫:循环不变量,我们清楚这一点之后,再去看那些循环条件或者是游标移动的位置,就很容易判断应该怎么写了。那么我们这里要找的元素8的位置也就找到了,直接返回下标right+1,或者是left就可以

我们看一下代码部分:

    public static int lower_bound(int[] nums, int target){int left = 0;int right = nums.length - 1;while (left <= right){ // 闭区间内查找,当left > right的时候区间为空 int mid = left + (right -left) / 2;if (nums[mid] < target){left = mid + 1; // [mid + 1, right]是不确定的} else {right = mid - 1; // [left, mid - 1]是不确定的}}return left; // left所指向的位置就是元素出现的初始位置}

左闭右开区间[left, right)

左闭右开区间和闭区间的情况相似,我们需要修改右游标的初始位置arr.length,因为右游标不再包括在区间内,也就是说再循环中[right, arr.length-1]的元素是确定好的;还需要修改的地方有右游标更新的位置,因为是开区间,所以直接移动到mid所在的位置就可以;最后是循环的终止条件,当left == right的时候区间为空,循环停止。下面是游标的初始位置:

在这里插入图片描述

那么我们开始循环:

  1. mid所指向的值为8,满足条件 ≥ t a r g e t \geq target target,我们将右游标移动至mid位置,并更新mid

    在这里插入图片描述

  2. mid所指向的值为7,满足条件 < t a r g e t < target <target,我们将左游标移动到mid+1的位置,并更新mid

    在这里插入图片描述

  3. mid所指向的值为7,满足条件 < t a r g e t < target <target,我们将左游标移动到mid+1的位置,并更新mid

    在这里插入图片描述

  4. 此时left == right,所有元素也都知道了大小,停止循环,并返回right。

代码部分

    public static int lower_bound(int[] nums, int target){int left = 0;int right = nums.length;while (left < right){ // 左闭右开区间内查找[left, right)int mid = left + (right -left) / 2;if (nums[mid] < target){left = mid + 1; // [mid + 1, right)是不确定的} else {right = mid; // [left, mid)是不确定的}}return right; // right所指向的位置就是元素出现的初始位置}

开区间(left, right)

原理差不多,就不一一画图了,需要修改:

  1. 左游标的初始位置-1,因为是开区间上面已经解释过,我们需要保证区间内的元素是没有被确定的,而区间外的元素已经都被确定完毕
  2. 右游标的初始位置arr.length
  3. 左游标更新的位置mid
  4. 右游标更新的位置mid
  5. 循环终止的条件left + 1 == right,此时区间内已经没有元素

代码部分

    public static int lower_bound(int[] nums, int target){int left = -1;int right = nums.length;while (left + 1 < right){ // 开区间内查找(left, right)int mid = left + (right -left) / 2;if (nums[mid] < target){left = mid; // (mid, right)是不确定的} else {right = mid; // (left, mid)是不确定的}System.out.println(left + " " + right);}return right; // right所指向的位置就是元素出现的初始位置}

变式

通过上面最简单的查找元素的初始位置,我们可以转换为更多的变式:

  1. 找到元素的初始位置

    这就是查找到元素初始位置的情况,如果有mid指向的元素比target大,那么就不断缩小右区间

  2. 找到元素的结束位置

    这种情况我们可以转化为:找到比target大1的元素的初始位置,也就是 m i d ≥ t a r g e t + 1 mid \geq target+1 midtarget+1

  3. m i d ≤ t a r g e t mid \le target midtarget

    这种情况可以转化为找到 > t a r g e t >target >target的元素位置,然后-1

  4. m i d < t a r g e t mid < target mid<target

    这种情况可以转换为找到 ≥ t a r g e t \geq target target的元素的位置,然后-1

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

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

相关文章

ubuntu中通过源码安装pointnet2_ops_lib

注&#xff1a;本帖所用环境为&#xff1a;ubuntu 24.04、 cuda 12.04 文章目录 1. 克隆 PointNet 源码库2. 安装依赖3. 编译 pointnet2_ops_lib4. 测试安装 1. 克隆 PointNet 源码库 首先&#xff0c;克隆 PointNet 的 GitHub 仓库&#xff1a; git clone https://github.co…

加密软件是怎么实现文件加密的

1、选择加密算法&#xff1a;加密软件支持多种加密算法&#xff0c;如对称加密算法&#xff08;如AES、DES&#xff09;和非对称加密算法&#xff08;如RSA&#xff09;。用户可根据需求和安全性要求选择合适的算法。 2、生成密钥&#xff1a;加密算法需要一定的密钥来对文件进…

代码随想录Day17 图论-1

DFS和BFS基础 做图论这部分的题目DFS和BFS少不了 DFS是深搜 沿着一条路一直搜索下去直到无法继续向下 再通过回溯 换一条路进行搜索 BFS是广搜 就是从当前节点出发 一直把当前节点所连接的所有节点都搜索过之后 进入下一节点在开始相同的搜索过程 98.所有可达路径 题意很简…

linux环境oracle11.2.0.4打补丁(p31537677_112040_Linux-x86-64.zip)

上传补丁及opatch工具 创建目录并上传opatch工具和补丁包 [oraclerhel64 ~]$ mkdir /u01/psu [oraclerhel64 ~]$ cd /u01/psu [oraclerhel64 psu]$ ll total 514572 -rw-r--r-- 1 oracle oinstall 391781147 Sep 23 17:37 p31537677_112040_Linux-x86-64.zip -rw-r--r-- 1 or…

iOS 顶级神器,巨魔录音机更新2.1正式版

嘿&#xff0c;这是黑猫。如果巨魔没有通话录音机&#xff0c;那它的价值至少减半。 用户的痛点就是商机&#xff0c;因此开发通话录音功能的巨魔开发者&#xff0c;不约而同地选择了付费制。 而在一众录音机中&#xff0c; TrollRecorder 巨魔录音机可以说是用户体验最好&am…

【深度学习】03-神经网络2-1损失函数

在神经网络中&#xff0c;不同任务类型&#xff08;如多分类、二分类、回归&#xff09;需要使用不同的损失函数来衡量模型预测和真实值之间的差异。选择合适的损失函数对于模型的性能至关重要。 这里的是API 的注意⚠️&#xff0c;但是在真实的公式中&#xff0c;目标值一定是…

STM32 的 SDIO 接口(基于STM32F429HAL库)

目录 一、引言 二、SDIO 控制器组成 1.时钟管理模块 2.命令通道模块 3.数据通道模块 4.中断管理模块 三、STM32F429 的 SDIO 特性 1.高速数据传输 2.兼容性强 3.灵活的配置选项 4.可靠性和稳定性 四、HAL 库中的 SDIO 相关结构和函数 1.SD_HandleTypeDef结构体…

基于SpringBoot+Vue的在线问诊管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

OpenCV特征检测(12)检测图像中的潜在角点函数preCornerDetect()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 计算用于角点检测的特征图。 该函数计算源图像的基于复杂空间导数的函数 dst ( D x src ) 2 ⋅ D y y src ( D y src ) 2 ⋅ D x x src − 2 …

vue使用PDF.JS踩的坑--部署到服务器上显示pdf.mjs viewer.mjs找不到资源

之前项目使用的pdf.js 是2.15.349版本&#xff0c;最近换了一个4.6.82的版本&#xff0c;在本地上浏览文件运行的好好的&#xff0c;但是发布到服务器&#xff08;IIS&#xff09;上打不开文件&#xff0c;控制台提示找不到pdf.mjs viewer.mjs。 之前使用的2.15.349pdf和viewer…

自动换行且带下划线的居中长标题的论文封面一种绘图实现

自动换行且带下划线的居中长标题的论文封面一种绘图实现 引言 在一些学位论文的封面上要求标题带有下划线&#xff0c;但长标题的情况下标题自动换行后下划线就会面临一些问题。 因此&#xff0c;往往需要一些特殊的处理。 在《如何制作自动换行且有定长下划线的论文封面模板…

第九节 Opencv自带颜色表操作

知识点&#xff1a;Look Up lTable&#xff08;LUT&#xff09;查找表 了解LUT查找表的作用与用法&#xff0c;代码实现与API介绍 -applyColorMap&#xff08;src,dst,COLORMAP&#xff09; -src表示输入图像 -dst表示输出图像 匹配到的颜色LUT&#xff0c;Opencv支持13种…

17.2 ksm源码讲解

本节重点介绍 : k8s资源对象的 buildStores构造函数注入MetricFamiliesk8s client-go 之 Reflector listAndWatch 方法watchHandler 监听更新&#xff0c;调用add等action 架构图总结 项目地址 地址 go get go get -v -d k8s.io/kube-state-metrics/v2v2.1.1源码分析 m…

【Godot4.3】自定义数列类NumList

概述 数列是一种特殊数组。之前写过等比、等差数列、斐波那契等数列的求取函数。今天就汇总到一起&#xff0c;并添加其他的一些数列&#xff0c;比如平方数、立方数、三角形数等。 这里我首先采用以前比较喜欢的静态函数库的写法&#xff0c;然后在其基础上改进为基于类继承…

大数据毕业设计选题推荐-国潮男装微博评论数据分析系统-Hive-Hadoop-Spark

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、PHP、.NET、Node.js、GO、微信小程序、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇…

[vulnhub] Jarbas-Jenkins

靶机链接 https://www.vulnhub.com/entry/jarbas-1,232/ 主机发现端口扫描 扫描网段存活主机&#xff0c;因为主机是我最后添加的&#xff0c;所以靶机地址是135的 nmap -sP 192.168.75.0/24 // Starting Nmap 7.93 ( https://nmap.org ) at 2024-09-21 14:03 CST Nmap scan…

Android中高级面试题笔记题理论知识大全(PDF免费下载)

Android中高级面试题笔记题理论知识大全(PDF免费下载) 基本上全覆盖了市面上中大厂的面试题&#xff0c;笔试题。而且持续更新。 而且现在市场行情非常不好&#xff0c;所以多学点&#xff0c;背点面试题&#xff0c;笔记题目总没有坏处&#xff0c;只有好处。想获取更多资料: …

手机上轻松解压并处理 JSON 文件

JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;在手机上有着广泛的应用场景。 首先&#xff0c;在数据传输方面&#xff0c;许多移动应用程序通过网络请求与后端服务器进行交互&#xff0c;而服务器端的 API 接口通常使用 JS…

[Redis][持久化][上][RDB]详细讲解

目录 0.前言1.RDB0.是什么&#xff1f;1.触发机制2.流程说明3.RDB文件的处理4.RDB的优缺点 0.前言 Redis ⽀持 RDB 和 AOF 两种持久化机制&#xff0c;持久化功能有效地避免因进程退出造成数据丢失问题&#xff0c;当下次重启时利⽤之前持久化的⽂件即可实现数据恢复 RDB ->…

Qt/C++ 了解NTFS文件系统,解析MFT主文件表中的常驻属性与非常驻属性

系列文章目录 整个专栏系列是根据GitHub开源项目NTFS-File-Search获取分区所有文件/目录列表的思路。 具体的如下: Qt/C 了解NTFS文件系统&#xff0c;了解MFT(Master File Table)主文件表&#xff08;一&#xff09; 介绍NTFS文件系统&#xff0c;对比通过MFT(Master File Tab…