直接上代码了,要求数组要是有序的。
说明一下,什么是二分查找呢?就是本来我们一般查找一个东西,一般会从头开始找,或者从后面开始,反正会找一个顺序,乱找的话就比较花时间,而二分查找就是总是从中间开始,每次都从现有查找结果的中间开始,不断缩小与真实值的距离。
def binary_search(list,item): #一个有序数组
low=0 #因为是有序数组,所以第一个位置的编号是0
high=len(list)-1 #low和high用于跟踪要在其中查找的列表部分
while low<= high: #只要范围没有缩小到质包含一个元素
mid=(low+high)//2 #就检查中间的元素,如果不是偶数,会向下圆整
guess=list[mid]
if guess==item: #找到元素了
return mid
if guess>item: #猜的数字大了
high=mid-1
else: #猜的数字小了
low=mid+1
return None #没有指定的元素
my_list=[1,3,5,7,9]
print(binary_search(my_list,3)) #表示3在里面的位置,从0开始,所以返回1
print(binary_search(my_list,-1)) # => None -1不在列表中,返回None
再做一下leetcode上的二分查找题目巩固下:
- 统计有序矩阵中的负数:
给你一个 m * n 的矩阵 grid,矩阵中的元素无论是按行还是按列,都以非递增顺序排列。
请你统计并返回 grid 中 负数 的数目。
- 首先,是有序数组,满足二分查找的要求,但是是个矩阵,就有点难了,我没有想法,怎么从中间开始呢?好像不需要二分吧?看下别人怎么做的。
看下官方解说:
注意到题目中给了一个性质,即矩阵中的元素无论是按行还是按列,都以非递增顺序排列,可以考虑把这个性质利用起来优化暴力。已知这个性质告诉了我们每一行的数都是有序的,所以我们通过二分查找可以找到每一行中从前往后的第一个负数,那么这个位置之后到这一行的末尾里所有的数必然是负数了,可以直接统计。
class Solution:
def countNegatives(self, grid: List[List[int]]) -> int:
return sum(bisect.bisect_left(g[:: -1], 0) for g in grid)
这个太牛逼了,以头抢地了,啥时候才能十秒写出这样的代码?o(╥﹏╥)o
bisect.bisect_left 该函数用入处理将会插入重复数值的情况,返回将会插入的位置,left表示从左边插入0的位置,这里举例就是,比如[5,4,-1,-2],那么0从左边插入的话,是在哪里插入呢?
应该是[5,4,0,-1,-2],那么0的位置是第三个,返回值是2。
可是他是从最后一个数字开始查找,也就是[-2,-1,4,5],返回值一样是2,但是这样可以知道0之前的一定比0小,所以可以直接sum。终于弄明白了o( ̄▽ ̄)d