二分查找的变形问题:
image.jpeg
变体一: 查找第一个值等于给定值的元素
比如,有下面这样一个有序数组,其中,a[5], a[6], a[7] 的值都是8,是重复的数据,我们希望查找第一个等于 8 的数据,也就是下标是 5 的元素。
image.jpeg
如果还用之前的代码,那么查找到 a[7] 就会直接返回了,所以需要修改一下代码:
def bsarch(a, n, value):
low = 0
high = n - 1
while low <= high:
mid = low + (high - low) >> 1
if a[mid] > value:
high = mid - 1
elif a[mid] < value:
low = mid + 1
else:
if mid == 0 or a[mid - 1] != value:
return mid
else:
high = mid - 1
return -1
变体二:查找最后一个值等于给定值的元素:
问题由前面的查找第一个变成了查找最后一个。
def bsarch(a, n, value):
low = 0
high = n - 1
while low <= high:
mid = low + (high - low) >> 1
if a[mid] > value:
high = mid - 1
elif a[mid] < value:
low = mid + 1
else:
if mid == n - 1 or a[mid + 1] != value:
return mid
else:
high = mid - 1
return -1
变体三:查找第一个大于等于给定值的元素:
比如,数组中存储了这样一组数据:3,4,6,7,10。查找第一个大于等于 5 的元素,就是 6.
def bsarch(a, n, value):
low = 0
high = n - 1
while low <= high:
mid = low + (high - low) >> 1
if a[mid] >= value:
if mid == 0 or a[mid - 1] < value:
return mid
else:
high = mid - 1
else:
low = mid + 1
return -1
变体四:查找最后一个小于等于给定值的元素:
比如,数组中存储了这样一组数据 3, 5, 6, 8, 9, 10, 最后一个小于等于 7 的元素就是6.
def bsarch(a, n, value):
low = 0
high = n - 1
while low <= high:
mid = low + (high - low) >> 1
if a[mid] > value:
high = mid - 1
else:
if mid == n - 1 or a[mid + 1] > value:
return mid
else:
low = mid + 1
return -1
二分查找更适合用在 ‘近似’查找问题,在这类问题上,二分查找的优势更加明显。比如上面提到的几种变体,用其他数据结构,比如散列表、二叉树就比较难实现了。