二分查找
二分查找使用前提:
1.有序数组(单调递增或递减)
2.无重复元素
而使用方法:
二分查找一般可以定义两种区间
1.全闭--[l, r] 相当于while l <= r
2.左闭--[l, r) 相当于while l < r
选择一种区间后就要时刻牢记区间的定义,在每次处理边界时会用到,否则写出来得代码就是靠蒙的
例如:
给一个有序数组A和一个目标值S,求目标值在数组中的下标,如果没找到返回-1
A = [-2,0,2,4,9,11] S = 9
第一种定义:全闭
分析:
一、目标值在全闭区间中
1.首先要使用while l <= r
2.处理边间
(1)首先找到数组的中间长度mid
(2)其次,根据A[mid] 与s对比,判断我们应该在哪个区间去搜索 --二分
<1> 当A[mid] > s,我们就应该在mid的左边去搜索(记住,数组是有序的递增的;如果数组有序递减搜索区间就要变成去mid右边搜索),即搜索区域变为[l, mid - 1],也就是把 r = mid - 1
为什么搜索区域不能是[l, mid]?--因为A[mid] > S 所以A[mid] 不会等于S,mid就不是我们要找到的值
为什么判断条件不能是A[mid] >= S?--我们要找的就是数组中等于S的值,如果判断条件是大于等于,那么当前的值到底是大于S(应该继续搜索),还是等于S呢(停止搜索)
<2> 当A[mid] < s,我们应该在mid右边搜索
<3> 当A[mid] == s,停止搜索
def search(A,s): l = 0 r = len(A) - 1 while l <= r: mid = (l + r) // 2 #找到中间位置 if A[mid] > s: #如果大于s,则搜索区间变为[l, mid - 1]即r = mid - 1 r = mid - 1 elif A[mid] < s: #如果小于s,则搜索区间变为[mid + 1, r]即l = mid + 1 l = mid + 1 else: #等于s则停止搜索 return mid return -1 A = [-2,0,2,4,9,11] S = 9 print(search(A,S))
结果为4
二、目标值在左闭区间
1.首先要使用while l < r
2.处理边间
(1)首先找到数组的中间长度mid
(2)其次,根据A[mid] 与s对比,判断我们应该在哪个区间去搜索 --二分
<1> 当A[mid] > s,我们就应该在mid的左边去搜索(记住,数组是有序的递增的;如果数组有序递减搜索区间就要变成去mid右边搜索),即搜索区域变为[l, mid),也就是把 r = mid
为什么搜索区域不是[l, mid - 1)?--记住我们的搜索区间是左闭,且A[mid]不等于s,所以mid肯定不是我们要找的值,对于开区间,数组的下标是到不了端点的。
例如:当mid = 9 ,l = 0时,我们如果用[l, mid - 1)搜索即[0, 8)搜索那么我们的搜索区间就相当于[0, 7](对于开区间,数组的下标是到不了端点的),这时是不是就漏掉了下标为8的值;而用[l , mid)搜索,则搜索区间为[0, 9)
这就相当于搜索区间[0, 8],这才是我们一个完整的搜索区间
为什么判断条件不能是A[mid] >= S?--我们要找的就是数组中等于S的值,如果判断条件是大于等于,那么当前的值到底是大于S(应该继续搜索),还是等于S呢(停止搜索)
<2> 当A[mid] < s,我们应该在mid右边搜索
<3> 当A[mid] == s,停止搜索
def search(A,s): l = 0 r = len(A) - 1 while l < r: mid = (l + r) // 2 #找到中间位置 if A[mid] > s: #如果大于s,则搜索区间变为[l, mid]即r = mid r = mid elif A[mid] < s: #如果小于s,则搜索区间变为[mid + 1, r]即l = mid + 1 l = mid + 1 else: #等于s则停止搜索 return mid return -1 A = [-2,0,2,4,9,11] S = 9 print(search(A,S))
上面两种就是标准的二分查找模板,所以在考虑二分查找时要时时刻刻牢记区间的定义,这样在处理边间时才不会糊涂。

浙公网安备 33010602011771号