二分查找及其应用

二分算法及其应用 例如,如果一名研究员有 4 篇论文,引用次数分别为 (1,100,2,3),则 h指数为 2,然而若引用次数为 (1,100,3,3)则 h 指数将会是 3。经过一段时间的学术研究,她已经发表了 N篇论文,并且她的第 i 篇论文得到了来自其他研究文献的 ci次引用。因为是有序的,所以可以比较f[i]是否与x相等,比较大小,大的话则说明x的位置比当前i大,反之则小。枚举每一个数,从小到大的枚举,与数组进行匹配,最后找到x的位置i,输出。总结:二分查找大大优化了搜索的范围,让我们高效的找到了全局的最优解。... 阅读详情

概述

二分查找算法是一种效率极高的算法,也是为数不多时间复杂度在O(logn)量级的算法。算法思想并不难理解,但是某些细节却十分复杂,因而本文尝试从一个通用框架入手,通过对不同细节的填补,生成在三种情况下适用的不同框架。同时后边给了一些二分查找的里边,便于读者练习。

框架与说明

通用二分查找框架

框架处理过程:

1. 初始化:为left和right赋值
2. 循环退出条件
3. 比较中值和目标值关系,分情况处理
	1. 相等
	2. 小于
	3. 大于

代码框架如下:

int binarySearch(int [] nums,int target) {
    int left = 0, right = ...;
    
    while(...){
        //防止溢出等同于mid = (left +right)/2
        int mid = left + (right - left)/2; 
        if(nums[mid] == target) {
            ...
        }else if (nums[mid] < target) {
            left = ...
        }else if (nums[mid] > target) {
            right = ...
        }
    }
    return ...
}

分析上边的框架,可能有两个奇怪的地方:

第一个是mid的计算方法比较奇怪

第二个整个if判断过程中没有else分支

其实这两个问题也是二分查找的两个重要点。

针对第一点mid如果使用传统的写法mid = (left + right)/2确实比较容易理解,但left和right直接相加可能会导致上溢出的风险,因而需要使用mid = left + (right - left)/2。

第二个问题可能更多是一个技巧,因为二分查找思想可能很容易理解,但是细节却比较难以捉摸,因而在使用二分查找时要把所有情况用else if 写清楚,而不要出现else,这样可以清晰的展现出所有分支的细节,便于理解和排错。

同时,在整个模板中,我们可以看到有好多省略号...标记,这个是容易出现细节问题的地方,也是我们在使用二分查找需要尤为注意的问题,后边会结合一些简单实例,来说明一下这些细节会有那些变化。

基本二分查找

image-20201028124753048
public int binarySearch(int[] nums, int target) {
    // 初始化,细节一:right此处复制为nums.length - 1,
    //相当于搜索区间为[left,righty]
    int left = 0, right = nums.length - 1;
    // 循环退出条件,细节二:由于细节一的原因,此处要使用left<=right
    //,从而保证能够搜索到right的位置
    while (left <= right) {
      // 计算中值
      int mid = left + (right - left) / 2;
      // 查找到目标结果直接返回对应索引的位置
      if (nums[mid] == target) {
        return mid;
      } else if (nums[mid] < target) {
        // 细节三:因为已经验证过mid位置,因此需要从[mid+1,right]区间开始查找
        left = mid + 1;
      } else if (nums[mid] > target) {
        // 细节四:原因同细节三
        right = mid - 1;
      }
    }
    // 区间内所有值都已搜索完毕,直接返回-1
    return -1;
  }

基于初始模板,我们可以很快写出基本的二分查找算法,但是针对实现过程中的一些细节,我们需要做一些说明:

  1. 为什么 while 循环的条件中是 <=,而不是 < ?

首先由于我们初始化的时候选择的右边界就是right = nums.length -1,也即右边界是可以被访问到的,所以我们在终止条件判断的时候需要加上这个等号,搜寻的时候,搜索区间为[left,right]一个闭区间。

这二者可能出现在不同功能的二分查找中,区别是:前者相当于两端都闭区间 [left, right],后者相当于左闭右开区间 [left, right),因为索引大小为nums.length 是越界的。

  1. 为什么 left = mid + 1,right = mid - 1?我看有的代码是 right = mid 或者left = mid,没有这些加加减减,到底怎么回事,怎么判断?

这个也是二分查找的重要细节,刚才我们说了此处的搜索区间是[left,right],因此当判断mid之后,我们需要将搜索区间锁定在[left,mid-1]、[mid+1,right]这两个区间中。后一种用法可能会在左边界查找、右边界查找中会用到。

左边界查找

代码实现:

public int leftBound(int[] nums, int target) {
    // 细节1:right赋值为length,意味着搜索区间范围左闭右开
    int left = 0, right = nums.length;
    // 细节2
    while (left < right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] == target) {
            // 细节3
            right = mid;
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            // 细节4
            right = mid;
        }
    }
    // 细节5
    return nums[left] == target ? left : -1;
}

左边界查找较之与基本二分查找多了几个细节点不同。

  1. 为什么 while(left < right) 而不是 <= ?

答:用相同的方法分析,因为 right = nums.length 而不是 nums.length - 1 。因此每次循环的「搜索区间」是 [left, right) 左闭右开。while(left < right) 终止的条件是 left == right,此时搜索区间 [left, left) 为空,
所以可以正确终止。

  1. 为何返回left?

答:因为搜索退出时一定是left==right因此即使返回的是right也影响不大。

右边界查找

代码实现:

public int rightBound(int[] nums, int target) {
    int left = 0, right = nums.length;
    while (left < right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] == target) {
            //细节1
            left = mid + 1;
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid;
        }
    }
    //细节2
    return nums[left - 1] == target ? left - 1 : -1;
}

这个相比左边界查找可能有两个细节地方改变:

  1. 中点值和目标值相同时,不直接返回而是要通过left = mid + 1将查找区间向右逼近,进而才能查找最右侧的值
  2. 返回值是left -1 ,主要是因为,在找到目标值之后做了一个left = mid +1 操作,从而实际我们想要的mid的值为left -1。

典型例题

1. 寻找旋转排序数组中的最小值

image-20201028191109284

基本思路:

在二分查找的过程中比较最左侧和最右侧值的大小,如果右侧小,则搜索【mid+1,right】区间,同时要注意一种情况,就是mid隔开了最小值,因此需要判断mid位置元素是否是最小的元素,如果不是将搜索区间改成【left,mid-1】。 如果左侧小则直接搜索【left,mid-1】

代码实现:

public int findMin(int[] nums) {
    int left = 0, right = nums.length - 1;
    int min = nums[left];
    while (left <= right) {
      int mid = ((right - left) >> 1) + left;
      if (nums[mid] < min) {
        min = nums[mid];
      }
      if (nums[left] < nums[right]) {
        right = mid - 1;
      } else if (nums[left] > nums[right]) {
        // 证明最小值在mid的前面
        if (mid > left && nums[mid] > nums[mid - 1]) {
          right = mid - 1;
        } else {
          left = mid + 1;
        }
      } else if (nums[left] == nums[right]) {
        return min;
      }
    }
    return min;

总结

通过对上边三种二分查找框架的掌握,大部分二分查找问题都可以解决,还是那句话,二分查找本身思想比较简单,但是细节很折磨人,但是针对某个问题,逐个分析其细节,最后大部分问题应该还是可以比较好的解决的。

二分查找实现及其应用 二分查找,应用广泛,将n个元素分成个数大致相同的两半,取a[n/2]与欲查找的x作比较,如果x=a[n/2]则找到x,算法终止。如果x<a[n/2],则我们只要在数组a的左半部继续搜索x(这里假设数组元素呈升序排列)。如果x>a[n/2],则我们只要在数组a的右半部继续搜索x。 阅读详情

相关推荐

精通二分查找算法及其实践应用

本文还有配套的精品资源,点击获取 简介:二分查找是一种高效的搜索算法,适用于有序数组。通过重复将搜索范围减半来快速定位目标元素,其时间复杂度为O(log n),空间复杂度为O(1)。本文深入解析了二分查找的原理、步骤、复杂度分析、适用场景以及代码实现,同时探讨了其在排序、三分查找和二分查找树等变体中的应用。二分查找不仅在理论上有其重要性,在实际编程和数据处理中也占据着核心地...

weixin_35811662的博客 1051

二分查找法的实现和应用汇总

在学习算法的过程中,我们除了要了解某个算法的基本原理、实现方式,更重要的一个环节是利用big-O理论来分析算法的复杂度。在时间复杂度和空间复杂度之间,我们又会更注重时间复杂度。 时间复杂度按优劣排差不多集中在: O(1), O(log n), O(n), O(n log n), O(n2), O(nk), O(2n) 到目前位置,似乎我学到的算法中,时间复杂度是O(log n),好像就数...

weixin_30763455的博客 516

劳特巴赫 Trace32 调试使用教程

详细介绍如何使用trace32进行调试

m0_56208280的博客 4万+

二分查找的简单运用

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一、pandas是什么? 二、使用步骤 1.引入库 2.读入数据 总结 前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。 提示:以下是本篇文章正文内容,下面案例可供参考 一、pandas是什么? 示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分

m0_50708613的博客 657

量化实战:用三种波动率模型给你的期货策略做个“体检”(附Python代码与螺纹钢案例)

本文深入探讨了三种专业波动率模型(Parkinson、Garman-Klass和Rogers-Satchell)在期货量化策略中的应用,并以螺纹钢期货为例,展示了如何通过Python实现这些模型进行多维度波动率分析。文章详细比较了不同模型的特点和适用场景,提供了动态仓位管理、止损策略优化等实战应用方案,帮助交易者更精准地评估市场风险,优化策略表现。

weixin_26824299的博客 460

Carla学习笔记(一)服务器跑carla本地显示窗口

其中host后替换为你的服务器IP,-carla-rpc-port和-p后为端口号,需要一致。python3 manual_control.py也可以替换为其他python脚本。因为电脑配置不够,所以在服务器跑carla,本地运行PythonAPI里的样例。把carla仓库的PythonAPI拷贝到本地,或者直接去官方里下载一下。

做题记录 4977

二分查找的学习与应用

在生活中,我们如果单单只是将书整理到书架上,那么我们找到一本书是比较困难的,因为我们需要一个个遍历书架上的书,但是如果我们将书按照拼音排序,那么对于我们寻找书是有帮助的,这就涉及到了我们二分查找的中一个基本思想----有序。

weixin_72437555的博客 750

【图神经网络】从0到1使用PyG手把手创建异构图

异构图的准确定义如下:异构图(Heterogeneous Graphs):一个异构图GGG有一组节点V=v1,v2,...,vnV=v_1,v_2,...,v_nV=v1​,v2​,...,vn​和一组边E=e1,e2,...,emE=e_1,e_2,...,e_mE=e1​,e2​,...,em​组成,其中每个节点和每条边都对应着一种类型,用TvT_vTv​表示节点类型的集合,TeT_eTe​表示边类型的集合,一个异构图有两个映射函数,分别将每个节点映射到其对应的类型ϕv:V→Tv\phi_v:V\rig

小哲的博客 7833

查找算法之二分查找

观察发现,在“双闭区间”表示中,由于对左右两边界的定义是相同的,因此缩小区间的 i , j 处理方法也是对称的,这样更不容易出错。二分查找,利用数据的有序性,通过每轮缩小一半搜索区间来查找目标元素。,元素从小到大排列。数组的索引取值范围为:0,1,2,⋯,n−1。首先,我们先采用“双闭区间”的表示,在数组 nums。定一个长度为 n 的排序数组 nums。接下来,以python与C++为例。中查找目标元素 target。

m0_62919535的博客 1879

YOLOv8改进 | 主干网络 | 增加网络结构增强小目标检测能力【独家创新——附结构图】

YOLOv8改进,小目标检测,yolov8

kay_545 6019

Python 爬虫实战:抓取新闻网站上的新闻标题和内容

随着信息化的进展,新闻网站已经成为人们获取新闻和时事资讯的主要途径。许多新闻网站提供了丰富的内容,涵盖了社会、政治、科技、娱乐等多个领域。通过抓取新闻网站的内容,我们可以分析新闻的趋势,获取某一领域的最新动态,甚至为数据分析和机器学习提供数据支持。本文将详细介绍如何使用 Python 编写爬虫,抓取新闻网站上的新闻标题和内容。requests:发送 HTTP 请求,获取页面内容。:解析 HTML 页面并提取数据。Selenium:抓取动态加载的网页内容。新闻API。

2201_76125261的博客 3407

二分查找模板及其应用

二分查找模板及其应用

byx的博客 1239

基于Simulink的压缩空气储能(Compressed Air Energy Storage, CAES)

压缩空气储能(CAES)是一种将电能转化为压缩空气存储在高压容器中,然后在需要时释放空气驱动涡轮机发电的技术。它具有大规模、长寿命和环境友好的特点,在电力系统中用于削峰填谷、频率调节和备用电源等应用。本项目将详细介绍如何在MATLAB/Simulink中搭建一个完整的基于压缩空气储能的系统,并提供具体的代码实现和设计步骤。如果你需要实现更复杂的控制逻辑,可以使用MATLAB Function模块。以下是一个简单的例子,展示了如何在该模块中实现一个条件逻辑:Matlab深色版本Kp = 1;

MHD0815的博客 1274

二分查找法及其应用

当数据量很大时宜采用该方法,采用二分查找法时,数据需要是排好序的。 一、二分查找法的形式 一种是采用闭区间,即在[low,high]之间查找,另外一种形式是左开右闭区间,形如[low,high) 如果在只是确定要查找的数是否在区间内出现,两种形式都可使用,但是当要求找的数的下限或上限时,用左开右闭区间较好,stl中用的就是这种形式 闭区间的算法步骤 (1)mid = (low+high)

多看多听多总结 1512

AUTOSAR AP——SM模块

对AUTOSAR AP中状态管理模块SM,从模块定义、总结等多方面进行了介绍。

weixin_43627682的博客 284

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

【二分查找的Java实现及其应用】

二分查找是一种在有序数组中查找特定元素的搜索算法。它的时间复杂度为 O(log n),对于大数据集具有较高的性能。

我是Java程序员廖志伟,感谢朋友们的支持! 1019

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

二分查找算法及其应用

二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。 查找过程 首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。 算法复杂度 二分查找的

weixin_43157935的博客 933

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

【二分查找法及其应用】

基本思路 设在升序序列 a [ low......high ] 查找的 k , 首先找`中间值 `mid= a [ ( low+high )/2 ] ; 然后`比较 k` 和 a [ mid ] , 分成三个情况: (1)k == a[ mid ] , 直接返回 a [ mid ] ; (2)k < a [ mid ] , 新的查找区域变为左子表 a [ low , mid-1 ] ; (3)k > a [ mid ] , 新的查找区域变为右子表 a [ mid+1 , high ] ; 下一次查找根据

指针不指南吗的博客 2040

【二分查找算法以及变种Leftmost、Rightmost查找及其应用】

【代码】【二分查找算法以及变种Leftmost、Rightmost查找及其应用】

qq_51240148的博客 358

C——二分查找法及其应用

定义一个左指针和一个右指针,初始时左指针指向数组的第一个元素,右指针指向数组的最后一个元素。计算左右指针的中间位置,即 mid = (left + right) / 2。将中间位置的元素与目标元素进行比较:如果中间元素等于目标元素,则找到了目标元素,返回位置。如果中间元素大于目标元素,则目标元素必然在左半部分,更新右指针为 mid - 1。如果中间元素小于目标元素,则目标元素必然在右半部分,更新左指针为 mid + 1。4.

2301_79075954的博客 307

二分查找及其简单应用

二分查找 var search = function(nums, target) { let left = 0; let right = nums.length-1; while(left <= right){ let middle = Math.floor(left +(right - left)/2); if(nums[middle]<target) { left = middle + 1; }el

weixin_45833462的博客 173

二分查找算法及其在数的范围问题中的应用

二分查找是一种高效的搜索算法,通过每次将搜索区间减半,将时间复杂度优化至O(log n)。其核心原理基于有序数据集合的快速定位,广泛应用于数据库索引、游戏AI等场景。在工程实践中,二分查找的变种如左右边界查找能解决数的范围等实际问题,需要注意整数溢出和边界条件处理。算法优化涉及统一框架设计和多种变体应用,理解其底层实现原理对提升编程能力至关重要。

weixin_33552698的博客 166

二分查找及其变化应用

经典的二分查找两次二分查找题:统计一个数字在排序数组中出现的次数。例如输入排序数组{1, 2, 3, 3, 3, 3, 4, 5}和数字3,由于3在这个数组中出现了4次,因此输出4。分析:对于该题,如果直接遍历很容易得到出现的次数,但是其时间复杂度为O(N)。因为数组是排序的所以我们可以考虑二分查找来加快速度。通过二分查找分别找到最左边的3和最右边的3位置,就可以计算得到3的个数,算法复杂度为O(l

oscarwin 545

(6)二分查找及其应用场景

数据结构&算法模块总结 (1)复杂度分析原理与方法 (2)数组与链表原理和使用场景讲解 (3)栈原理与应用场景讲解 (4)队列原理与应用场景讲解 (5)递归原理与虚拟机栈场景应用 1.传统二分查找模板问题 public int bsearch(int[] a, int n, int value) { int low = 0; int high = n - 1; while (low <= high) { int mid = (l

大表哥的博客 3633
上一篇: 常见的位操作及其应用
下一篇: 视频语义分割基准数据集与评估方法
vcjmhg
博客等级 码龄11年 27粉丝 94原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值