Python二分法查找及变种分析
基于Python3
普通二分法查找目标值的index
二分法查找的思路很简单,先确定好列表nums的一头start一尾end,中间值middle根据头尾数值之和用地板除法除以2,即(start + end) // 2。将目标值target与nums[middle]进行比对,这时候有3种结果:
- nums[middle] > target
- nums[middle] < target
- nums[middle] = target
以上3种情况前2种不断循环,直到满足第3种跳出循环。
情况1
说明target在前半段,所以end=middle-1
情况2
说明target在后半段,所以start=middle+1
情况3
说明target就是nums[middle],所以返回middle,这是跳出循环的方式之一
所以到此可以写出循环体中的代码,如下:
middle = (start + end) // 2
if target > nums[middle]:
start = middle + 1
elif target < nums[middle]:
end = middle - 1
else:
return middle
但是,万一一直达不到第3种的条件呢?即target压根不在列表nums中,这就出现了情况4
情况4
我们循环到最后阶段一定是start=middle-1=end-2,即start与middle与end紧挨着。这时候,我们将start,middle,end代入if语句进行分析,
- nums[middle] > target,所以赋值end=middle-1,这时end且又和start相等
- nums[middle] < target,所以赋值start=middle+1,这时start且又和end相等
那么此时还有最后一个值需要判断,以上2种情况再代入循环体,此时有start=end=middle。若没有nums[middle]=target,则跳出循环(此为跳出循环的方式之二)返回-1
很明显,start与end一直互相逼近,但是start一直小于end的,要不要加上等于这个条件呢?别忘了只有start=end,才能够对列表中的最后一个元素进行判断。
完整代码如下:
def binarySearch(nums, target):
start = 0
end = len(nums) -1
while start <= end:
middle = (start + end) // 2
if target > nums[middle]:
start = middle + 1
elif target < nums[middle]:
end = middle - 1
else:
return middle
return -1
if __name__ == "__main__":
List = [1,4,4,5,7,7,8,9,9,10]
print(List)
print(binarySearch(List, 1))
# output
# [1, 4, 4, 5, 7, 7, 8, 9, 9, 10]
# 0
变种二分法查找
给定一个排序的整数数组(升序)和一个要查找的整数target,用O(logn)的时间查找到target第一次出现的下标(从0开始),如果target不存在于数组中,返回-1。
普通的二分查找只要找到target就行了,这个必须考虑到列表中重复的元素。
也就是说,即便找到了也不能跳出循环体。那么怎样才能跳出循环体呢?
别忘了跳出循环的方式有2种,刚才只是封住了第1种,还有第2种呢。即while的设置条件。很明显,start小于end是必须的循环条件的,而start大于end肯定是跳出循环的条件,那么start=end是跳出还是不跳出呢?首先要清楚start=end的意义是什么,即经过迭代此时列表nums中的选择区域变成了一个元素,循环的作用是将这最后一个元素选出来。
跳出循环,去判断是哪种可能。这个元素只有2种可能:不满足target或者是满足target的第一个元素。
可能一:不满足target的过程
注意,和普通二分法情况一样,循环到最后阶段一定是start=middle-1=end-2,即start与middle与end紧挨着。这时候,我们将start,middle,end代入if语句进行分析,
- nums[middle] > target,所以赋值end=middle-1,这时end且又和start相等
- nums[middle] < target,所以赋值start=middle+1,这时start且又和end相等
此时start=end,跳出循环,判断不满足target,需要return -1
可能二:满足target的第一个元素的过程
如何确定是满足target的第一个元素?
先明白循环中找到第一个等于target的nums[middle]元素不跳出循环应该做什么。很明显,应该搜寻nums[start:middle]区域,所以要赋值end=middle,即搜寻新的nums[start:end]区域。再次循环,此时只剩下2种结果,再找到等于target的nums[middle] 或者 找不到了
结果1再找到等于target的nums[middle]
- 第一步得到middle = (start + end) // 2
- 有target = nums[middle]
- 赋值end=middle
- 进入新的循环,搜寻新的nums[start:end]区域,依然面临2种结果
结果2再找不到等于target的nums[middle]
- 第一步得到middle = (start + end) // 2
- 一定有nums[middle] < target而不是nums[middle] > target,因为nums是递增的。
- 此时start = middle + 1
- 进入新的循环,搜寻新的nums[start:end]区域,依然面临2种结果
以上2种结果互相交错,循环到最后阶段一定是start=middle-1=end-2,即start与middle与end紧挨着。这时候,我们将start,middle,end代入if语句进行分析,
- nums[middle] < target,所以赋值start=middle+1,这时start且又和end相等,此时start=end,跳出循环,判断nums[start] == target,需要return start。
- nums[middle] = target,所以赋值end=middle,得到start=middle-1,再带入循环,有middle = (start + end) // 2,得到start=middle=end-1。
此时最后一步又分为二,1若nums[middle] < target,所以赋值start=middle+1,这时start且又和end相等,此时start=end,跳出循环,判断nums[start] == target,需要return start。2若nums[middle] = target,所以赋值end=middle,得到start=middle=end,跳出循环,判断nums[start] == target,需要return start。
def binarySearch(nums, target):
start = 0
end = len(nums) -1
while start < end:
middle = (start + end) // 2
if target > nums[middle]:
start = middle + 1
elif target < nums[middle]:
end = middle - 1
else:
end = middle
if nums[start] == target:
return start
return -1
if __name__ == "__main__":
List = [1,4,4,5,7,7,8,9,9,10]
print(List)
print(binarySearch(List, 4))
# output
# [1, 4, 4, 5, 7, 7, 8, 9, 9, 10]
# 1
Python二分法查找及变种分析的更多相关文章
- python 二分法查找思考理解小白向け
首先说一下二分法查找的思路.这是面向小白的课程,大佬请让步谢谢 给定一个有序的序列(必须是排好序的)例如[1,2,3,4,5,6,7,8,9,10,20,30,400],然后我们查询一个元素出现的坐标 ...
- python中两种方法实现二分法查找,细致分析二分法查找算法
之前分析了好多排序算法,可难理解了呢!!(泣不成声)这次我要把二分查找总结一下,这个算法不算难度特别大,欢迎大家参考借鉴我不喜欢太官方的定义,太晦涩的语言,让人看了就头晕.我希望加入我自己的理解,能帮 ...
- python 二分法查找实例(递归、循环)
二分法,主要应用于有序序列中,原理是每次查找都将原序列折半,逐渐缩小查找范围的一种算法. 需求 要求在一个有序序列中,例如[0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30 ...
- python 二分法查找
这个也是之前写的程序,现在把它贴上来 #!/usr/bin/python import os os.system('clear') def binsearch(seq,x,low,high): mid ...
- Python二分法查找
1.1二分前提是有序,,否则不可以2分,2分查找的时间复杂度是O(log n):排序后二分查找到适当的位置插入数值 lst = [37,99,73,48,47,40,40,25,99,51] def ...
- python 二分法查找字典中指定项第一次出现的索引
import time #引入time库,后续计算时间. inform_m = {} #创建母字典 inform_s = {} #母字典下嵌套的子字典 #给母字典添加键-值 for i in rang ...
- Python【day 14-4】sorted filter map+递归文件夹+二分法查找
def func(x): #普通函数 return x*x ret1 = func(10) #匿名函数 f = lambda x:x*x # 匿名函数写法: 匿名函数名=lambda 参数:返回值 ' ...
- python 内置函数(二) 进阶函数 递归内容及二分法查找 知识点
1,lambda: 匿名函数 2.sorgted() 排序函数 3,filter() 过滤函数 筛选 4,map() 映射函数 5.递归 6.二分法 一. 匿名函数: lambda lamb ...
- 查找算法:二分法查找及其python实现案例
承接上一篇:查找:顺序查找与二分法查找,将二分法更多详细的python实现解题写下笔记. 简单方法 ''' 二分法查找在列表中的用户输入值,返回index 三种情况跳出循环体: LR相邻 LR位置重合 ...
随机推荐
- Java 泛型在实际开发中的应用
java泛型是对Java语言的类型系统的一种扩展,泛型的本质就是将所操作的数据类型参数化.下面我会由浅入深地介绍Java的泛型. 一:泛型出现的背景 在java代码里,你会经常发现类似下边的代码: p ...
- 使用镜像仓库托管自己构建的Docker镜像
自己构建的Docker镜像,默认存储在本机中,Docker有提供某些方式分享这些镜像,但不是主流的镜像分享方式,也有违于开源社区的共享精神. 本文介绍如何使用GitHub托管Dockerfile:使用 ...
- LinkedList源码浅析(jdk1.8)
LinkedList由双向链表实现的集合,因此可以从头或尾部双向循环遍历. LinkedList的操作都是对双向链表的操作,理解双向链表的数据结构就很容易理解LinkedList的实现. 双向链表由带 ...
- [Oracle]高水位标记(HWM)
(一)高水位标记(High Water Mark,HWM)的概念 所谓高水位标记,是指一个已经分配的段中,已经使用的空间与未使用的空间的分界线.在表的使用过程中,随着数据的不断增多(insert),H ...
- css3-transition过渡属性
transition主要是用于一个元素的一种状态到另一种状态的一个过渡的过程,不能够主动触发,必须依赖于事件,例如hover伪类选择器. 一,transition简写 transition:要过渡的属 ...
- 【HTML】html5新属性-datalist
摘要: 为实现输入域自动填充的效果 方法一: jquery-ui的autocomplete方法, 不是jquery 自带的方法. 方法二: 采用html5新特性,datalist,例子如下:坏处很明显 ...
- java泛型(整理)
1 泛型基础知识 泛型需要理解两个关键点:1)类型擦除 2)类型转换 1)类型擦除 泛型有个很重要的概念,是类型擦除.正确理解泛型概念的首要前提是理解类型擦除(type erasure). Java中 ...
- hadoop系列三:mapreduce的使用(一)
转载请在页首明显处注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/7224772.html 一:说明 此为大数据系列的一些博文,有空的话会陆续更新,包含大数据的 ...
- goroutine 加 channel 代替递归调用,突破递归调用的层级限制
package main import ( "fmt" "github.com/davecgh/go-spew/spew" "github.com/B ...
- Java 编程 订单、支付、退款、发货、退货等编号主动生成类
订单.支付.退款.发货.退货等编号主动生成类 在商城网站中,订单编号的自动生成,ERP中各个单据的编号自动生成,都可以按照一下的方式来自动生成. 第一步:定义常量订单编号前缀.订单编号起始数.订单编号 ...