二分模板
在使用二分查找时,要确保数据是有序的,并根据具体情况处理边界条件。
在具体使用时,只需将nums
替换为你的数组,target
替换为你要查找的目标值,然后根据具体问题对找到目标值的情况和没找到目标值的情况进行相应的操作。
注意条件的设置
def binary_search(nums, target):
left, right = 0, len(nums) - 1
while left <= right:
mid = left + (right - left) // 2
if nums[mid] == target:
# 找到目标值的情况
return mid # 或者执行其他操作
elif nums[mid] < target:
left = mid + 1
else:
right = mid - 1
# 没找到目标值的情况
return -1 # 或者执行其他操作
详解和更多案例看:
算法第三期——二分法(Python)_二分法python-CSDN博客
# 查找57
def bin_search(a, n, x): # 在数组a中找数字x,返回位置
left = 0 # 二分法的左端点
right = n # 二分法的右端点 0~n-1:左闭右开[0,n)
while left < right: # 右端点大于左端点则继续二分
mid = (right + left) // 2 # 折半前的中间点。//:整除
if a[mid] >= x:
right = mid # 小于中间点则中间点作为右端点
else: # a[mid] < x,只是大于,所以要left = mid + 1
left = mid + 1 # 大于中间点则中间点作为左端点
return left
n = 200
a = [0] + [i for i in range(2, 202,2)]
test = 57
pos = bin_search(a, n, test) # 二分搜索
print("find =", a[pos]) # find = 58
在单调递增序列a中查找x或x的后继:
# 查找57
def bin_search(a, n, x): # 在数组a中找数字x,返回位置
left = 0 # 二分法的左端点
right = n # 二分法的右端点 0~n-1:左闭右开[0,n)
while left < right: # 右端点大于左端点则继续二分
mid = (right + left) // 2 # 折半前的中间点。//:整除
if a[mid] >= x:
right = mid # 小于中间点则中间点作为右端点
else: # a[mid] < x,只是大于,所以要left = mid + 1
left = mid + 1 # 大于中间点则中间点作为左端点
return left
n = 200
a = [0] + [i for i in range(2, 202,2)]
test = 57
pos = bin_search(a, n, test) # 二分搜索
print("find =", a[pos]) # find = 58
"""
当找到x时,判断x是否是序列中的最后一个元素,如果不是,则返回x的后继;
如果x不存在于序列中,则返回小于x的最接近值作为x的前驱。
"""
def search_successor(a, x):
left, right = 0, len(a) - 1
successor = None
while left <= right:
mid = left + (right - left) // 2
if a[mid] == x:
if mid < len(a) - 1:
successor = a[mid + 1]
break
elif a[mid] < x:
left = mid + 1
else:
successor = a[mid]
right = mid - 1
return successor
# 测试用例
a = [1, 3, 5, 7, 9, 11, 13, 15]
result = search_successor(a, 3)
print(f"x的后继是:{result}") # x的后继是:5
在单调递增序列a中查找x或x的前驱
def bin_search(a, n, x):
left = 0
right = n
while left < right:
mid = (left+right+1)//2 # 不加上1会陷入死循环
if a[mid] <= x:left = mid
else: right = mid - 1
return left
n = 200
a = [0] + [i for i in range(2, 202,2)]
test = 57 # # 猜57或57的后继
pos = bin_search(a, n, test) # 二分搜索
print("find =v ", a[pos]) # find = 56
"""
使用二分查找来在单调递增序列a中查找元素x或x的前驱。
维护左右指针来缩小搜索范围,根据中间元素与x的大小关系来更新左右指针。
当找到x时,我们判断x是否是序列中的第一个元素,如果不是,则返回x的前驱;
如果x不存在于序列中,则返回大于x的最接近值作为x的后继。
"""
def search_predecessor(a, x):
left, right = 0, len(a) - 1
predecessor = None
while left <= right:
mid = left + (right - left) // 2
if a[mid] == x:
if mid > 0:
predecessor = a[mid - 1]
break
elif a[mid] < x:
predecessor = a[mid]
left = mid + 1
else:
right = mid - 1
return predecessor
# 测试用例
a = [1, 3, 5, 7, 9, 11, 13, 15]
x = 6
result = search_predecessor(a, x)
print(f"x的前驱是:{result}") # x的前驱是:5
实数域的二分查找
因为实数是无限的,不能像整数那样精确地进行比较。在实数域上的二分查找通常使用近似比较的方式来判断是否找到目标值
在实数域上进行二分查找可能存在精度问题,特别是当目标值非常接近区间边界时。在使用该模板时,请根据具体情况调整精度控制epsilon
的值。
"""
引入了一个很小的精度控制epsilon,用于判断二分区间的结束条件。
当区间的长度小于epsilon时,认为已经找到了一个足够接近目标值的近似解,即使不是完全相等也可以接受。
"""
def binary_search(left, right, target):
epsilon = 1e-6 # 精度控制
while left + epsilon < right:
mid = (left + right) / 2
if mid == target:
# 找到目标值的情况
return mid # 或者执行其他操作
elif mid < target:
left = mid
else:
right = mid
# 没找到目标值的情况
return -1 # 或者执行其他操作