当前位置: 首页 > news >正文

算法通关村第九关——透彻理解二分查找

1.前言

常见的查找算法有顺序查找、二分查找、插值查找、斐波那契查找、树表查找、分块查找、哈希查找等。如果进行归类,那么二分查找、插值查找(一种查找算法)以及斐波那契查找都可以归为插值查找(大类)。而插值查找和斐波那契查找是在二分查找的基础上的优化查找算法。

这些算法中最重要的就是Hash查找二分查找

记住:凡是涉及到在排好序的地方(全局或部分)查找的都可以考虑使用二分查找来优化查找效率

插值查找使用的公式为:
x = ( k e y − a r r [ i ] ) ( r − i ) a r r [ r ] − a r r [ i ] x = \frac{(key-arr[i])(r-i)}{arr[r]-arr[i]} x=arr[r]arr[i](keyarr[i])(ri)
其中,ir分别代表数组的第一个和最后一个索引, key代表待查找的元素

分块查找是折半查找和顺序查找的一种改进方法,分块查找由于只要求索引表是有序的,对块内节点没有排序要求,因此特别适合解决节点动态变化的情况。

2.基本查找

基本查找也就是顺序查找,不需要在乎数组是否排序,缺点是效率较低

function search(arr, key) {for (let index = 0; index < arr.length; index++) {if (arr[index] === key) {return index;}}
}

3.二分查找与分治

分治就是把整体拆分为局部,一个复杂的问题可以拆分成很多相似的小问题。二分查找是将中间结果与目标进行比较,一次去掉一半。
在这里插入图片描述

3.1 循环方法

// 二分查找——循环方式
function binarySearch(array, low, high, target) {while (low < high) {let mid = (low + high) / 2;if (array[mid] < target) {low = mid + 1} else if (array[mid] > target) {high = mid - 1;} else {return mid;}}return -1;
}

/ 运算符效率较低,可以写成移位符 >>, 还存在一个问题,当lowhigh 过于大时,low + high可能会溢出,可以将 let mid = (low + high) / 2;改为let mid = low + ((high - low) >> 1);,只要lowhigh 没有溢出,mid就不会溢出。

最终代码如下:

function binarySearch(array, low, high, target) {while (low < high) {let mid = low + ((high - low) >> 1);if (array[mid] < target) {low = mid + 1} else if (array[mid] > target) {high = mid - 1;} else {return mid;}}return -1;
}

3.2 递归方法

按照递归三步法,代码如下:

// 二分查找——递归方式
function binarySearch(array, low, high, target) {// 递归终止条件if (low <= high) {let mid = low + ((high - low) >> 1);// 不同情况判断if (array[mid] === target) {return mid;} else if (array[mid] < target) {return binarySearch(array, mid + 1, high, target);} else {return binarySearch(array, low, mid - 1, target);}}// 表示没有搜索到return -1;
}

4.有重复元素的二分查找

在上面的基础上,如果元素存在重复,要求如果重复就找左侧第一个,比如[1, 2, 2, 2, 3, 3, 3, 4, 5, 6],要返回第一个2的索引值——1

分析:基于上面简单的二分查找,在这里我们找到target不要着急返回,而是在重复元素的这个区间继续进行查找,一直找到最左侧的重复元素,再返回最左侧元素的重复索引。在重复元素的这个区间继续进行查找方法有好几种,第一种方法比较简单,就是使用线性查找,一个一个的向左进行查找直到找到最左侧的重复元素。

// 元素中有重复的二分查找,在上面的基础上,元素存在重复,如果重复则找左侧第一个
function binarySearchOfRepeat(array, target) {// 特判if (array === null || array.length  === 0) {return -1;}let left = 0;let right = array.length - 1;while (left <= right) {let mid = left + ((right - left) >> 1);if (array[mid] < target) {left = mid + 1;} else if (array[mid] > target) {right = mid - 1;} else {// 找到目标值后,还应该继续向左侧进行线性查找,直到左侧没有重复值while (mid !== 0 && array[mid] === target) {mid--;}// 如果一直找到了开头还都是重复值,就返回开头if (mid === 0 && array[mid] === target) {return mid;}// 不然就返回mid + 1return mid + 1;}}return -1;
}

这里之所以返回mid + 1,是因为假如序列为[1, 2, 2, 2, 2, 3, 3],当target=3,当内层的while循环退出时,nums[mid]=2,因此必须返回mid + 1

第二种方法呢就是使用折半查找:

function binarySearchOfRepeat(array, target) {// 特判if (array === null || array.length  === 0) {return -1;}let left = 0;let right = array.length - 1;while (left <= right) {let mid = left + ((right - left) >> 1);if (target < array[mid]) {right = mid - 1;} else if (target > array[mid]) {left = mid + 1;} else {// 如果存在重复元素,在该段重复数组区间内进行折半查找while (left < mid) {				let midLeft = left + ((mid - left) >> 1);// 如果array[midLeft] === target,直接去掉一半右边的重复值if (array[midLeft] === target) {mid = midLeft;} // 如果array[midLeft] !== target,说明超过了重复区间,让left =  midLeft + 1,继续查找else {left =  midLeft + 1;}}return left;}}return -1;
}

拓展——使用递归进行有重复元素的二分查找

再拓展一下,使用递归方法。

function binarySearchOfRepeat(array, target, left, right) {// 不能发生边界逾矩if (left > right) {return -1;}let mid = left + ((right - left) >> 1);if (array[mid] === target) {// 在重复区间内使用递归来找到最左侧的位置let leftmostInRepeat = binarySearchOfRepeat(array, target, left, mid - 1);// 如果没有重复返回mid,如果有重复返回重复区间最左侧值索引return (leftmostInRepeat === -1) ? mid : leftmostInRepeat;} else if (target < array[mid]) {return binarySearchOfRepeat(array, target, left, mid - 1);} else {return binarySearchOfRepeat(array, target, mid + 1, right);}
}function findLeftmostRepeatIndex(array, target) {if (array === null || array.length === 0) {return -1;}return binarySearchOfRepeat(array, target, 0, array.length - 1);
}

相关文章:

算法通关村第九关——透彻理解二分查找

1.前言 常见的查找算法有顺序查找、二分查找、插值查找、斐波那契查找、树表查找、分块查找、哈希查找等。如果进行归类&#xff0c;那么二分查找、插值查找&#xff08;一种查找算法&#xff09;以及斐波那契查找都可以归为插值查找&#xff08;大类&#xff09;。而插值查找…...

【字节跳动青训营】后端笔记整理-4 | Go框架三件套之GORM的使用

**本人是第六届字节跳动青训营&#xff08;后端组&#xff09;的成员。本文由博主本人整理自该营的日常学习实践&#xff0c;首发于稀土掘金。 我的go开发环境&#xff1a; *本地IDE&#xff1a;GoLand 2023.1.2 *go&#xff1a;1.20.6 *MySQL&#xff1a;8.0 本文介绍Go框架三…...

【TI毫米波雷达笔记】UART串口外设配置及驱动(以IWR6843AOP为例)

【TI毫米波雷达笔记】UART串口外设初始化配置及驱动&#xff08;以IWR6843AOP为例&#xff09; 最基本的工程建立好以后 需要给SOC进行初始化配置 int main (void) {//刷一下内存memset ((void *)L3_RAM_Buf, 0, sizeof(L3_RAM_Buf));int32_t errCode; //存放SOC初…...

C#---第十九课:不同类型方法的执行顺序(new / virtual / common / override)

本文介绍不同类型的方法&#xff0c;在代码中的执行顺序问题&#xff1a; 构造方法普通方法&#xff08;暂用common代替&#xff09;、虚方法&#xff08;Virtual修饰&#xff09;、New方法&#xff08;new修饰&#xff09;三个优先级相同overide方法&#xff08;会替换virtual…...

[pytorch]torch.cuda用法以及判断显卡是不是存在问题

常见用法&#xff1a; torch.cuda.is_available() # 查看是否有可用GPU torch.cuda.device_count() # 查看GPU数量 torch.cuda.get_device_capability(device) # 查看指定GPU容量 torch.cuda.get_device_name(device) # 查看指定GPU名称 torch.cuda.empty_cache() # 清空程序占…...

JUC——多线程补充

前置可看 Java——多线程和锁_java多线程锁_北岭山脚鼠鼠的博客-CSDN博客 线程创建的三种方式 Thread、Runnable、Callable Thread类 Runable接口 Callable接口 Lamda表达式 Lamda表达式_北岭山脚鼠鼠的博客-CSDN博客 静态代理模式(Thread类的原理) 如下代码中 真实对象…...

代码随想录第32天|122.买卖股票的最佳时机 II,55. 跳跃游戏 ,45. 跳跃游戏 II

122.买卖股票的最佳时机 II 122. 买卖股票的最佳时机 II 思路比较简单 class Solution {public int maxProfit(int[] prices) {int res0,sum0;for(int i0;i<prices.length-1;i){if(prices[i1]-prices[i]>0){sumprices[i1]-prices[i];}ressum>res?sum:res;}return …...

Linux:Nginx服务与搭建

目录 一、Nginx概述 二、Nginx三大作用&#xff1a;反向代理、负载均衡、动静分离 三、Nginx和Apache 3.1Nginx和Apache的差异 3.2Nginx和Apache的优缺点比较 四、编译安装niginx 五、创建Nginx 自启动文件 六、Nginx的信号使用 6.1信号 七、升级 nginx1.18 nginx1.2…...

4、什么是NoSQL

4、什么是NoSQL NoSQL NoSQL Not Only SQL&#xff0c;就是不仅仅是SQL的意思 泛指非关系型数据库&#xff0c;随着web2.0的诞生&#xff01;传统的关系型数据库很难对付web2.0时代&#xff0c;因为web2.0时代又很多数据大爆炸新生的产物比如视频、音乐、大数据产生的其他的数…...

如何自己实现一个丝滑的流程图绘制工具(一)vue如何使用

背景 项目需求突然叫我实现一个类似processOn一样的在线流程图绘制工具。 这可难倒我了&#xff0c;立马去做调研&#xff0c;在github上找了很多个开源的流程图绘制工具&#xff0c; 对比下来我还是选择了 bpmn-js 原因&#xff1a; 1、他的流程图是涉及到业务的&#xff0c…...

ReoGrid.NET集成到winfrom

ReoGrid一个支持excel操作的控件,支持集成到任何winfrom项目内。 先看效果图: 如何使用&#xff1a; 使用ReoGrid自带excel模版设计工具先设计一个模版,设计器如下&#xff1a; 具体例子看官方文档 代码示例如下&#xff1a; var sheet reoGridControl1.CurrentWorksheet; …...

Elasticsearch实现增删改查

调用elasticsearch通常使用restful风格请求&#xff0c;这里记录一些常用的Java API和Postman Url Java API调用Es 1. 查询总文档数 Testvoid getAllCount() { // RestHighLevelClient clientnew RestHighLevelClient(RestClient.builder(new HttpHost("192.168…...

Rust 学习笔记(卷二)

文章目录 Rust 学习笔记&#xff08;卷二&#xff09;八、工程1. package 和 cratepackage 总览包根&#xff08;crate root&#xff09; 2. 模块初识模块单个源文件中的嵌套模块使用具有层级结构的源文件构造嵌套模块 3. 文档4. 使用第三方包5. 打包自己的包 九、标准库十、多…...

android amazon 支付接入

流程&#xff1a; 申请 Amazon 开发者帐号 ---> 在 amazon 控制台添加应用 ---> 添加应用内商品&#xff08;消费类商品&#xff0c;授权类商品&#xff0c;订阅类商品&#xff09;---> 导出 JSON 文件 --->集成 Amazon 支付 ---> 将导出的 JSON 文件 copy 到 …...

Vue2-快速搭建pc端后台管理系统

一.推荐二次开发框架 vue-element-admin Star(84k)vue-antd-admin Star(3.5k) 二.vue-element-admin 官网链接:https://panjiachen.github.io/vue-element-admin-site/zh/ 我这里搭建的是基础模版vue-admin-template(推荐) # 克隆项目 git clone https://github.com/PanJi…...

【产品文档】团队介绍PPT模板

今天和大家免费分享团队介绍的PPT模板。团队介绍是向他人展示团队的实力、专业性和能力的重要方式。通过一个有力的团队介绍&#xff0c;您可以突出团队的成员、经验、技能和取得的成就&#xff0c;从而增加信任、吸引合作伙伴、客户或投资者的兴趣 【模板预览】 动态演示效果…...

组件库的使用和自定义组件

目录 一、组件库介绍 1、什么是组件 2、组件库介绍 3、arco.design 二、组件库的使用 1、快速上手 2、主题定制 3、暗黑模式 4、语言国际化 5、业务常见问题 三、自定义组件 2、组件开发规范 3、示例实践guide-tip 4、业务组件快速托管 一、组件库介绍 1、什么是…...

网站和API支持HTTPS,最好在Nginx上配置

随着我们网站用户的增多&#xff0c;我们会逐渐意识到HTTPS加密的重要性。在不修改现有代码的情况下&#xff0c;要从HTTP升级到HTTPS&#xff0c;让Nginx支持HTTPS是个很好的选择。今天我们来讲下如何从Nginx入手&#xff0c;从HTTP升级到HTTPS&#xff0c;同时支持静态网站和…...

UnitTest笔记: 拓展库DDT的使用

DDT (Data-Drivers- Tests) 允许使用不同的测试数据运行同一个测试用例&#xff0c;展示为不同的测试用例。 第一步&#xff1a; pip安装 ddt 第二步&#xff1a; 创建test_baidu_ddt.py 1. 测试类要使用ddt 修饰 2. 不同形式的参数化&#xff1a; 列表&#xff0c;字典&a…...

裂缝检测,只依赖OPENCV,基于YOLO8S

裂缝检测&#xff0c;只依赖OPENCV&#xff0c;YOLOV8S 现在YOLOV8S训练目标非常方便&#xff0c;可以直接转换成ONNX让OPENCV调用&#xff0c;支持C/PYTHON&#xff0c;原理很简单&#xff0c;自己找博客&#xff0c;有兴趣相互交流...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述&#xff1a;指针 vs. 引用&#xff08;类比其他语言&#xff09;一、指针基础概念二、指针声明与初始化三、指针操作符1. &&#xff1a;取地址&#xff08;拿到内存地址&#xff09;2. *&#xff1a;解引用&#xff08;拿到值&#xff09; 四、空指针&am…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲

文章目录 前言第一部分&#xff1a;体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分&#xff1a;体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释

以Module Federation 插件详为例&#xff0c;Webpack.config.js它可能的配置和含义如下&#xff1a; 前言 Module Federation 的Webpack.config.js核心配置包括&#xff1a; name filename&#xff08;定义应用标识&#xff09; remotes&#xff08;引用远程模块&#xff0…...