赞
踩
二分算法是编程中非常常见和常用的算法,即便如此我之前也没有想到 Python 官方竟然有一个专门的模块实现了该算法的大部分操作,该模块为 bisect
。
实际上,该模块提供的函数主要用于这样的场景,即在每次使用其中的函数向列表中插入一个元素后,无需对列表进行排序的同时可以保证该列表一直都是有序的。这对于列表元素很多,且元素之间的比较非常耗时的场景能很好的提高代码的效率。
"""Bisection algorithms.""" def insort_right(a, x, lo=0, hi=None): """Insert item x in list a, and keep it sorted assuming a is sorted. If x is already in a, insert it to the right of the rightmost x. Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. """ lo = bisect_right(a, x, lo, hi) a.insert(lo, x) def bisect_right(a, x, lo=0, hi=None): """Return the index where to insert item x in list a, assuming a is sorted. The return value i is such that all e in a[:i] have e <= x, and all e in a[i:] have e > x. So if x already appears in the list, a.insert(x) will insert just after the rightmost x already there. Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. """ if lo < 0: raise ValueError('lo must be non-negative') if hi is None: hi = len(a) while lo < hi: mid = (lo+hi)//2 if x < a[mid]: hi = mid else: lo = mid+1 return lo def insort_left(a, x, lo=0, hi=None): """Insert item x in list a, and keep it sorted assuming a is sorted. If x is already in a, insert it to the left of the leftmost x. Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. """ lo = bisect_left(a, x, lo, hi) a.insert(lo, x) def bisect_left(a, x, lo=0, hi=None): """Return the index where to insert item x in list a, assuming a is sorted. The return value i is such that all e in a[:i] have e < x, and all e in a[i:] have e >= x. So if x already appears in the list, a.insert(x) will insert just before the leftmost x already there. Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. """ if lo < 0: raise ValueError('lo must be non-negative') if hi is None: hi = len(a) while lo < hi: mid = (lo+hi)//2 if a[mid] < x: lo = mid+1 else: hi = mid return lo # Overwrite above definitions with a fast C implementation try: from _bisect import * except ImportError: pass # Create aliases bisect = bisect_right insort = insort_right
实际上,该模块非常简单,只是针对二分算法,通过 4 4 4 个函数实现了 二分算法的 4 4 4 个常用操作:
bisect_left(a, x, lo=0, hi=None)
该函数在假定 a
为有序序列的前提下,返回一个索引 i
,该索引确定了应该在何处插入元素 x
后可以确保 a
仍是有序序列。
该函数的返回值 i
满足如下性质:
a[:i]
中任意元素 e
,都有 e < x
;a[i:]
中任意元素 e
,都有 e >= x
。因此,如果 x
已经存在于 a
中,那么 a.insert(i, x)
会在 a
中已有的 x
中,在最左边 x
的前一个位置处插入 x
。
其中可选的参数 lo
(默认为
0
0
0)以及 hi
(默认为 len(a)
)用于确定二分查找的边界。
bisect_right(a, x, lo=0, hi=None)
该函数在假定 a
为有序序列的前提下,返回一个索引 i
,该索引确定了应该在何处插入元素 x 后可以确保 a
仍是有序序列。
该函数的返回值 i
满足如下性质:
a[:i]
中任意元素 e
,都有 e <= x
;a[i:]
中任意元素 e
,都有 e > x
。因此,如果 x
已经存在于 a
中,那么 a.insert(i, x)
会在 a
中已有的 x
中,在最右边 x
的后一个位置处插入 x
。
其中可选的参数 lo
(默认为
0
0
0)以及 hi
(默认为 len(a)
)用于确定二分查找的边界。
insort_left(a, x, lo=0, hi=None)
该函数将元素 x
插入 a
中,确保 插入前 a
是有序的前提下,插入后 a
也是有序的。
如果 x
已经存在于 a
中,那么元素 x
将会被插在最左侧那个 x
的前一个位置。
其中可选的参数 lo
(默认为
0
0
0)以及 hi
(默认为 len(a)
)用于确定二分查找的边界。
insort_right(a, x, lo=0, hi=None)
该函数将元素 x
插入 a
中,确保 插入前 a
是有序的前提下,插入后 a
也是有序的。
如果 x
已经存在于 a
中,那么元素 x
将会被插在最右侧那个 x
的后一个位置。
其中可选的参数 lo
(默认为
0
0
0)以及 hi
(默认为 len(a)
)用于确定二分查找的边界。
下面是自定义实现:
def binary_search_left(self, nums: List[int], target: int) -> int:
low, high = 0, len(nums) - 1
while low <= high:
mid = low + (high - low) // 2
if nums[mid] == target:
high = mid - 1 # 缩小搜索的上界
elif nums[mid] < target:
low = mid + 1
else:
high = mid - 1
return low
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。