对于二分查找的思考

工业组态软件Intouch(单机版)入门{第一篇} 通俗来讲Intouch就是一个能将PLC里的信号显示在画面上的软件。 阅读详情

由于我对python3相对比较熟悉,所以编程语言采用python3.

问题

问题:给定一个非空浮点数升序列表,和一个浮点数,如果这个浮点数在列表中,则返回最小索引,否则返回-1

问题的形式化

问题的形式化描述:
输入:非空浮点数升序列表alist,浮点数num
输出:索引index

涉及的基本概念

不管是使用迭代的写法还是使用递归的写法,在思考编程中不可避免要对基本概念进行明确。基本概念是思考的基石,通过它们我们抽象问题,并且检验结果。

那么有哪些基本概念呢?查找的话,需要考虑你要查找的东西即查找对象和限定的查找区域即查找域,查找区域一般用一个列表表示。然后要考虑当前查找的范围,针对数组,就是查找区间,这个区间可以使用子数组表示,也可以使用数组的索引区间表示,这里考虑到需要返回索引,我们使用索引区间表示。还要考虑的一个点就是有序数组的元素大小比较关系,也就是序关系和相等。最后,还要考虑返回值。

二分查找的想法,就是通过将查找对象与二分点值进行大小比较将查找区间长度缩减一半,最终查找区间长度只有1,就可以通过一次大小比较确定输出index还是-1。这个过程中需要考虑的概念是初始查找区间,查找区间长度,二分点,继续缩减条件, 查找区间变换公式,查找区间长度变换公式,最终状态,返回值。

基本概念的代码化

下面的代码化,我不追求简洁,而是追求清晰,即更好地呈现出基本概念。

查找问题的基本概念

  • 查找对象: num
  • 查找域:alist
  • 查找区间:[left, right]
  • 序关系:<,>
  • 相等:
def isEqual(a, b):
    if abs(a-b)<1e-7:
        return True
    else:
        return False

注意,相等关系要先于序关系进行判断,也就是:相等,不相等(包含<,>)

  • 返回值:index 或者-1

二分查找问题的基本概念

  • 初始查找区间:[left=0, right=len(alist)-1]
  • 查找区间长度:length = right-left+1
  • (左)二分点:mid = left + (right - left) // 2
  • (右)二分点:mid = right - (right - left) // 2
  • 继续缩减条件:查找区间长度大于1,即length > 1
  • 查找区间变换公式:如果是返回最小索引则使用左二分点,如果是返回最大索引则使用右二分点,此部分以及本节后续部分显示的都是只考虑返回最小索引的情形
if isEqual(num, alist[mid]):
	left, right = left, mid
elif num<alist[mid]:
	left, right = left, mid - 1
elif num>alist[mid]:
	left, right = mid + 1, right
  • 查找区间长度变换公式:下面只是为了讲解,并不是严谨的代码
if isEqual(num, alist[mid]):
	length = mid - left + 1
elif num<alist[mid]:
	length = mid - 1 - left + 1
elif num>alist[mid]:
	length = right - (mid+1)+ 1

命题:在继续缩减条件length>1下,(左)二分点在[left,right]中,并且变换后的查找区间长度均大于等于0且小于变换前的长度(特别地,如果查找对象在查找域中,则长度始终大于等于1,但是如果查找对象不在查找域中,则长度可能为0,即right-left=-1)
证明:我们使用变化前的区间表达变换后的区间长度:

  1. isEqual(num, alist[mid])时有
    1=<mid-left+1 = (right-left)//2+1<right-left+1
  2. num<alist[mid]时有
    0=<mid-left=(right-left)//2<right-left+1
  3. num>alist[mid]时有
    0=<right-mid=(right-left)-(right-left)//2<right-left+1

这个命题,保证了缩减持续进行,直到达到最终状态

  • 最终状态:[left, left]即length=1即right-left=0(在查找对象不在查找域时,是会出现[left, left-1]的状态的,所以有两个最终状态,虽然编程时可以同等处理,但是概念上要清晰)
    注意,我们将查找区间作为我们的这三个状态表达中的最基本概念。一般最终状态对应的是最小规模的原问题。最小规模非空有序列表就是只含有一个元素的列表(但是由于缩减过程,导致[left, left-1],也是最小规模问题,所以我们加一个length判断,为了让alist[left]总有意义,我们加上越界判断)。

此时,就剩下最后的比较,并据此给出返回值了:

# 判断越界条件,虽然此时left肯定不会越界,但是为了代码更加通用加上了
if left>=len(alist) or right<0 or right<left:
	return -1
	
if isEqual(num, alist[left]):
	return left
else:
	return -1

总结以上,得到求解代码:

def binarySearch(alist, num):
	# 初始化查找区间和查找区间长度
	left, right = 0, len(alist)-1
	length = right - left + 1
	
	# 在缩减条件成立时应用查找区间变换公式,直到达到最终状态
	while length>1:
		mid = left + (right - left) // 2
		if isEqual(num, alist[mid]):
			left, right = left, mid
		elif num<alist[mid]:
			left, right = left, mid - 1
		elif num>alist[mid]:
			left, right = mid + 1, right
		length = right - left + 1

	# 依据最终状态,给出返回值
	if left>=len(alist) or right<0 or right<left:
		return -1
	if isEqual(num, alist[left]):
		return left
	else:
		return -1
	
def isEqual(a, b):
    if abs(a-b)<1e-7:
        return True
    else:
        return False
        
if __name__ == "__main__":
	alist1 = [1., 2., 2., 3.2, 5., 6.]
	alist2 = [2., 2]
	alist3 = [1., 1]
	alist4 = [3,3]
	num = 2
	
	print(binarySearch(alist1, num))

验证

一个问题是,上一节的返回值确实给出了问题的解吗?转化到基本概念上,也就是如果查找对象在查找域中,那么最终状态的查找区间是否就是最小索引呢?

最一开始,最小索引当然在查找区间中,于是只需证明下面的命题。

命题:如果查找对象在查找域中,那么缩减查找区间的操作会让最小索引保持在缩减后的查找区间中。
证明:还是分三种情况讨论。

  1. isEqual(num, alist[mid])时
    因为[left, right]中有最小索引,而此时的mid必定大于等于最小索引,所以[left,mid]中必有最小索引。

  2. num<alist[mid]时,可知最小索引小于等于mid-1于是可以。

  3. num>alist[mid]时,可知最小索引大于等于mid+1于是可以。

左二分点vs右二分点

这一节我们讨论最微妙的细节。

我们首先明确,因为要保留最小索引,在 isEqual(num, alist[mid])时,我们要将查找区间变换到[left,mid]。而为了让区间长度严格减小,必须保证mid<right,这就要求二分点mid必须是左二分点。如果不好理解的话,考虑查找对象2和查找域[2.,2.],则查找区间为[left, right=left+1],则此时的左二分点就是left而右二分点就是right,此时只有取左二分点才能缩减区间长度。

左右指针框架

这一节,我们做一点抽象化的扩展。把上面的代码形成一种思维框架。上面的问题,输入的是列表,输出的是索引,所以我们使用索引区间表示查找区间,而最为关键的就是查找区间的两个端点指针

第一部分:左右指针初始化,循环条件(循环变量)初始化

left, right = xxx, yyy
循环条件初始化

第二部分:在循环条件满足时,对左右指针进行更新,并更新循环条件(循环变量)

while 循环条件:
	左右指针更新公式
	循环变量更新公式

第三部分:确定最终状态,即循环条件的临界破坏情况,一般对应最小规模的问题。在最终状态下,求解最小规模问题。

求解最小规模问题,使用左右指针确定返回值

把这三部分结合起来,一般写代码就不会有遗漏了,而且条理清晰。

所以,我们发现什么了呢?其实不管是递归也好,迭代也好,我们的策略都是具象和抽象的平衡:

  • 具体的问题,求解最小规模问题
  • 抽象化概念,确定缩减变量,缩减条件,缩减变量的更新公式,把大规模问题缩减为最小规模问题。这个过程要保持解的不变性,以及缩减的有效性。为此,可以使用集合论的思考方法,确定”可行域“,缩减”可行域“,考虑"可行域"的度量。

上面的左右指针框架,实际上就是用左右指针表达出可行域和可行域的度量,并且用左右指针来验证解的不变性,以及缩减的有效性。

相关推荐

模糊综合评价模型

一.引子 1.数学归纳法:同高中知识 2.秃子悖论:秃子悖论 这俩个例子都是类似于“量变引起质变”的道理,而在数学中我们把这类问题的性质叫做“模糊性”,在生活中我们也经常能遇到一些模糊的概念,比如年轻、帅、很少很多… 二.概述 模糊综合评价法是一种基于模糊数学的综合评价方法。该综合评价法根据模糊数学的隶属度理论把定性评价转化为定量评价,即用模糊数学对受到多种因素制约的事物或对象做出一个总体的评价。它具有结果清晰,系统性强的特点,能较好地解决模糊的、难以量化的问题,适合各种非确定性问题的解决。——来自百度百

The__Tyche的博客 2万+

二分查找——mid=(left+right)/2溢出

1、int型变量 int 是一种整型变量,占用 4 字节 32 比特时的取值范围是- 2147483648~2147483647,占用 2 字节 16 比特时的取值范围是- 32768~32767; 2、mid=(left+right)/2 二分查找时,求取中间值的操作步骤,写法mid = (left + right) / 2,这种写法存在问题。原因:left可能不断增大,如果到极限状态,也就是left达到了right-1的地步的时候刚好数组的长度又很大,那么就可能导致left + right的溢出出

weixin_42322256的博客 5678

电力电子技术(13)——大功率可控整流电路

目录引言2.6.1 带平衡电抗器的双反星形可控整流电路电路结构的特点接平衡电抗器的原因平衡电抗器使得两组三相半波整流电路同时导电的原理分析谐波分析2.6.2 多重化整流电路概述原理目标1)移相多重联结2)多重联结电路的顺序控制3重晶闸管整流桥顺序控制带平衡电抗器的双反星形可控整流电路(是多重化整流电路的重要形式之一)的特点:适用于低电压、大电流的场合。多重化整流电路的特点:绕组的极性相反的目的:消除直流磁通势如图所示,虽然两组相电流的瞬时值不同,但是平均电流相等而绕组的极性相反,所以直流安匝(电流*匝数)互

weixin_45589295的博客 1万+

二分查找那点事

我周围的人几乎都认为二分查找很简单,但事实真的如此吗?二分查找真的很简单吗?并不简单。看看 Knuth 大佬(发明 KMP 算法的那位)怎么说的: Although the basic idea of binary search is comparatively straightforward, the details can be surprisingly tricky… 这句话可以这样理解:思路很简单,细节是魔鬼。 本文就来探究几个最常用的二分查找场景:寻找一个数、寻找左侧边界、寻找右侧边界。 而且

fkuner的博客 963

手把手教你搞定爱思唯尔LaTeX投稿:从模板到PDF生成的全流程避坑指南

本文详细介绍了使用LaTeX投稿爱思唯尔期刊的全流程避坑指南,包括模板选择、文件结构规范、投稿系统文件上传策略、PDF生成与检查等关键步骤。特别强调了避免常见错误如宏包冲突、图片丢失和参考文献问题,并提供了投稿后的应急方案和高阶自动化校验脚本,帮助研究者顺利完成投稿。

weixin_42525289的博客 510

手把手教你搞定国民技术N32G031的Keil开发环境(附Pack包和JLink配置)

本文详细指导如何搭建国民技术N32G031的Keil开发环境,包括Keil MDK安装与激活、Pack包导入、JLink调试器配置等关键步骤。特别针对新手常见问题提供解决方案,帮助开发者快速上手N32G031系列MCU的开发工作。

cuangu9341的博客 424

为什么二分法算法中最好写int mid = left + (right-left)/2;

在经典二分查找法算法题中, 需要取数组中间元素的位置,那么第一反应不难写出int mid = (left + right) / 2; 但是这么写其实会有⼀个问题,就是可能会发生数值越界,left+right很有可能会超出int的范围。 最好写int mid = left + (right-left)/2;这样可以很大程度上避免数组越界的问题。 ...

qq_40476342的博客 1583

U8二次开发CO-基于Net8调用COM对象

本文章介绍的U8二次开发CO技术,就是基于微软COM组件技术,使用微软开源的编程框架Net6/7/8/9来调用U8的COM组件,完成基本的登录认证,工作流处理,数据库操作等。

pccai的博客 5501

【LeetCode刷题笔记/LeetCode704】二分查找left+(right-left)/2

二分查找使用条件:数组有序且元素无重复 二分查找经常用到left+(right-left)/2 代替mid = (left + right) / 2 原因就是left+right很容易超过int范围,导致mid = (left + right) / 2 容易溢出,而==mid = left + (right - left) / 2 ==不容易溢出,所以写二分时要用mid = left + (right - left) / 2。 题目:LeetCode704.二分查找 区间:[left,right]下: i

柠檬鱼的博客 688

信号与电源完整性5:轨道塌陷噪声/电源轨道噪声分析及降低解决方案

经过上一节关于串扰的分析,我们已经清楚,噪声问题不仅仅来源于信号网络;电源和地网络所产生的噪声,被反馈到其所在的元器件和信号网络时,其破坏力也是巨大的;本节所讨论的轨道塌陷噪声就是一个典型的实例。在经过电源的地网络的电流发生改变时,在电源和地之间的阻抗上将产生一个压降;由于该压降的产生,用电元件的电压将直接被拉低,甚至可能对电路产生功能性的错误。接下来硬小二将详细的分析电源轨道噪声和降低其的解决方法。...

fydar的博客 2241

泰山派rk3566 audio音频基础介绍

本文介绍了嵌入式系统中音频处理的基础知识,重点围绕RK3566平台的音频子系统展开。文章首先解释了音频信号从模拟到数字的转换过程,包括采样率、位深和声道等核心概念。随后详细分析了嵌入式音频开发中的关键接口:I2C用于控制音频编解码器,I2S作为专用音频数据传输总线,以及PCM作为原始音频格式和ALSA设备抽象的双重含义。通过对这些基础概念和接口的解析,为在RK3566平台上进行音频驱动开发和应用调试提供了理论基础。

qq_37077309的博客 294

二分查找重难点总结(边界条件、循环条件、mid计算方法等)

1. 二分查找易错点总结 二分查找中有三个点需要特别注意: 搜索范围的左右边界,即left = 0还是left = -1,right = nums.lengh-1 还是right = nums.lengh; 搜索停止(循环结束)的条件,即while(left < right)与while(left <= right)的选择问题; 搜索时中间值能否加入左/右边界,即right = mid 还是right = mid-1,left = mid还是left = mid+1; mid怎么计算,即mid

热爱技术,热爱生活! 7599

电力负荷预测 | 电力系统负荷预测模型(Python线性回归、随机森林、支持向量机、BP神经网络、GRU、LSTM)

电力负荷预测 | 电力系统负荷预测模型(Python线性回归、随机森林、支持向量机、BP神经网络、GRU、LSTM)

天天酷科研的博客 3189

二分查找——【查找问题】解析及思考

题目要求在有序数组中查找元素首次出现的位置。给定n个有序数字和m次查询,每次查询需要返回目标数字在数组中第一次出现的下标,若不存在则返回-1。 解题思路采用二分查找法,通过不断缩小查找范围来高效定位元素。关键点在于处理重复元素时保证找到首个出现的位置:当中间值≥目标时继续在前半段搜索,否则搜索后半段。最终检查找到的位置是否匹配目标值。 输入输出规模较大,需使用快速IO方法。程序实现简洁,时间复杂度为O(m log n),适用于题目给定的数据范围。

2403_89185994的博客 827

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

关于用JAVA实现二分查找的一点思考

二分查找作为一种最基础的查找方法,它的代码过程就不再赘述了,我用的是rank()递归的方法。 今天只是浅谈一下由二分查找这个案例延伸的一些思考。 我用的是JAVA语言来实现,JAVA语言的输入通常都用Scanner类来实现,我想进行的是 用户输入一个有序数组,然后输入想要查询的元素,最后控制台输出元素所在的位置。 首先要解决的就是JAVA的数组输入问题,JAVA最好用的输入类还是Scanner类,但Scanner类里默认的输入只有字符串型、整数型、和浮点型数据,并不能让我想要的数组型数据进行输入。

Ben_Jamin的博客 204

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

关于二分查找的一些思考

最近在做二分查找的算法,发现二分查找并不是想象的那么简单,尤其是终止条件,已经mid的取值问题,总是让我晕头转向,下面以一个例子,说一下我对二分查找的理解归纳: leetcode:剑指 Offer 53 - I. 在排序数组中查找数字 I 统计一个数字在排序数组中出现的次数。 示例 1: 输入: nums = [5,7,7,8,8,10], target = 8 输出: 2 示例 2: 输入: nums = [5,7,7,8,8,10], target = 6 输出: 0 限制: 0 <= 数组长

Bain2020的博客 297

关于二分查找的深入思考以及模板

二分查找的伪代码 二分的本质:对于一组有序的数据,这里以数组为例 left = 0, right = n -1 while (left <= right) mid = (left + right) / 2 case x[mid] < t: left = mid + 1; x[mid] = t: p = mid; break; ...

眼逮调试者的博客 162

关于二分查找的思考

算法思想 对一个顺序存储的线性表,设立head、rear、min三个指针,mid=(head+rear)/2,对于奇数个数的表,mid刚好在中间位置,对于偶数个数的表,mid在length/2-1的位置。 因为有序的特性,假设为递增序列,那么当head<=rear的情况下(等号一定要取,否则可能出现目标元素在表头或者表尾但是循环就已经结束了)。 当L[mid]>Target,说明目标...

Show me the code 374

二分查找的几点思考

二分查找的几点思考 很早听说90%的程序员写不出正确的二分查找程序,对此颇为怀疑也颇为惶恐。怀疑的是,二分查找真的很难写吗?惶恐的是,怀疑的我能否在短时间内写出一个正确的二分查找程序?为了自己能成为10%中的一员,在此特别总结了二分查找算法。 二分查找又称折半查找,用于在有序序列

4013

对于二分查找的一点思考

对于二分法的一点浅薄思考与总结 前言 二分查找的边界判断是做该类题目的难点。当检索了相关书籍和网络文章后,发现while循环内有多种可能(取不取等号),left和right(或定义为low和high)也有多种可能(有时候直接为mid,有时候 -1,有时候 +1)。可能由于大家认为二分查找过于基础,大部分的文章对于具体的条件判断和值的修改没有一个完整的描述,更多的都是直接给出一个模板或是既成的代码,看完后,对于边界条件的撰写,自己仍是云里雾里,故萌发了对各个情况做详细讨论的念头(当然可能有简单问题复杂化之嫌)

weixin_45069476的博客 402

二分查找的思考

当 nums[mid] >= target 时 right = mid - 1 表示当nums[mid] == target 时不会直接返回mid,因为mid很可能不是边界值,并且因为该函数是求左边界所以调整right,最后可能的左边界的索引就是left了。同理当nums[left] > nums[mid] 时,说明mid和right处于同一段有序部分,mid和right是有序的,当target处于这一段时,更新left。二分查找很常见的一个算法,但真写起来需要注意的细节还挺多的。

weixin_45865491的博客 458

二分查找,你思考过这些问题吗?

大厂多次考察的原因是什么呢? 面试者非常容易写错二分查找的边界条件,尤其对于二分查找变种题型。 这篇文章教会你写边界条件的通用思考方式,适用所有变种题型,不需要死记硬背。学会之后,面试前再看一遍,保证顺利bug-free。...

liuxiaoran的专栏 450

LeetCode 二分查找的一些思考

二分查找适用于有序数组(拓展理解二分查找)特殊题目下,数组是否有序并不重要,比如我们把数组分为:左半边数组,mid,右半边数组。我们先判断,mid是否满足题目条件,是就直接返回;

qq_38781075的博客 333

关于二分查找的总结和思考

模板二分法查找,只有当目标在数组内才能找到准确索引索引下标。当不存在于数组内时,我们依然可以借助二断性找到边界并进行处理。但是需要对于3和4这种超出边界的情况需要特殊处理。

lhm的博客 790
上一篇: python中print输出到文件中
下一篇: wps的excel筛查出包含指定字段的行
math_computer
博客等级 码龄8年 43粉丝 176原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值