Python-二分查詢演算法bisect模組
目錄
簡介
方法
二分查詢
目標值區間左側
bisect_left
(a, x, lo=0, hi=len(a))
在 a 中找到 x 合適的插入點以維持有序。引數 lo 和 hi 可以被用於確定需要考慮的子集;預設情況下整個列表都會被使用。如果 x 已經在 a 裡存在,那麼插入點會在已存在元素之前(也就是左邊)。如果 a 是列表(list)的話,返回值是可以被放在 list.insert(index,object)
的第一個引數的。
返回的插入點 i 可以將陣列 a 分成兩部分。左側是 all(val < x for val in a[lo:i])
,右側是 all(val >= x for val in a[i:hi])
。
>>> from bisect import *
>>> lst = [1,2,2,5]
>>> bisect_left(lst,4)
3
>>> lst[:3]
[1, 2, 2]
>>> lst[3:]
[5]
對於列表lst來說,以bisect_left返回的index為界限,lst[:index]為小於x的,lst[index:]為大於或等於x的。
>>> lst.insert(bisect_left(lst,4),4)
>>> lst[3]
4
使用insert方法插入x後,x就是在bisect_left返回的那個索引位置
原始碼
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
注意,原始碼使用的是(lo+hi)//2,如果使用模組刷題時超時(Python自動轉為大數運算,時間過長),可自己寫個二分查詢,改為lo+(hi-lo)//2。
目標值區間右側
bisect.bisect_right
(a, x, lo=0, hi=len(a))
bisect.bisect
(a, x, lo=0, hi=len(a))
類似於bisect_left
(a, x, lo=0, hi=len(a)),但是返回的插入點是 a 中已存在元素 x 的右側。
返回的插入點 i 可以將陣列 a 分成兩部分。左側是 all(val <= x for val in a[lo:i])
,右側是 all(val > x for val in a[i:hi])
。
>>> bisect_right(lst,4)
4
>>> lst[:4]
[1, 2, 2, 4]
>>> lst[4:]
[5]
對於列表lst來說,以bisect_left返回的index為界限,lst[:index]為小於或等於x的,lst[index:]為大於x的。
>>> lst.insert(bisect_right(lst,4),4)
>>> lst[4]
4
注意,已存在的4是lst[3],新插入的4是lst[4]
插入【可不學】
目標值區間左側
bisect.
insort_left
(a, x, lo=0, hi=len(a))
將 x 插入到一個有序序列 a 裡,並維持其有序。如果 a 有序的話,這相當於 a.insert(bisect.bisect_left(a, x, lo, hi), x)
。要注意搜尋是 O(log n) 的,插入卻是 O(n) 的。
注意,是insort_left,不是insert_left,意思是insert到一個sort後的序列。
>>> insort_left(lst,3)
>>> lst
[1, 2, 2, 3, 4, 4, 5]
原始碼
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.
"""
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
a.insert(lo, x)
目標值區間左側
bisect.
insort_right
(a, x, lo=0, hi=len(a))
bisect.
insort
(a, x, lo=0, hi=len(a))
類似於insort_left
(a, x, lo=0, hi=len(a)),但是把 x 插入到 a 中已存在元素 x 的右側。
>>> insort_right(lst,3)
>>> lst
[1, 2, 2, 3, 3, 4, 4, 5]
注:看原始碼發現真的沒有效能提升,裡面就是呼叫的insert,可以不學插入這兩個函式。
參考
更多python相關內容:【python總結】python學習框架梳理
本人b站賬號:lady_killer9
有問題請下方評論,轉載請註明出處,並附有原文連結,謝謝!如有侵權,請及時聯絡。如果您感覺有所收穫,自願打賞,可選擇支付寶18833895206(小於),您的支援是我不斷更新的動力。