程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

二分查找 Python bisect 內置模塊

編輯:Python

二分查找 第一課

  • 第一部分 搞清 bisect 模塊
    • 實例
    • 總結:
  • *35.搜索插入位置
  • 2089.找出數組排序後的目標下標
  • Python bisect 內置模塊
  • Python bisect 源碼

第一部分 搞清 bisect 模塊

* 模塊只針對 [升序列表]

i, j = 0, len(a) # *[0, len(a)) 半開半閉區間
''' bisect_left 左側插入位置 '''
while i < j:
mid = i + j >> 1
if a[mid] < target: i = mid + 1 # 遞增 < i 三者關系,先判斷小於
else: j = mid
return i
''' bisect_right 右側插入位置 '''
while i < j:
mid = i + j >> 1
if a[mid] > target: j = mid # 先判斷大於
else: i = mid + 1
return i

實例

from bisect import *
a = [1, 2, 6, 6, 6, 8] # 升序
bisect_left(a, 4) # 插入位置 2, 對應元素 6 
bisect(a, 4) # 同上
bisect_left(a, 6) # 同上
bisect(a, 6) # 插入位置 5, 對應元素 8 

總結:

目標存在,左是最左 x;右是最右 x 的右鄰居
目標不存在,左右相同,都是大於目標的元素位置。

  1. 注意是*插入位置
  2. 只針對*升序
  3. target 不存在,返回右鄰居的位置;存在 bisect_left 返回第一個目標位置, bisect_right
    返回最後一個目標的右鄰居的位置。
  4. 三者關系:bisect_left、<、i ;bisect_right、>、j
  5. 條件 while i < j: 返回 i = j

*35.搜索插入位置

*區分:插入位置與目標位置

class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
return bisect_left(nums, target)
# 右查找在目標存在時與眾不同,沒有重復元素,右插入位置 - 1 = 左插入位置 
i = bisect_right(nums, target)
return i-1 if nums[i-1] == target else i

2089.找出數組排序後的目標下標

class Solution:
def targetIndices(self, nums: List[int], target: int) -> List[int]:
nums.sort()
i = bisect_left(nums, target)
j = bisect_right(nums, target)
return list(range(i, j))

Python bisect 內置模塊

文檔
源代碼: Lib/bisect.py
bisect,是實現 二分 (bisection) 算法 的模塊,能夠保持序列順序不變的情況下對其進行 二分查找和插入

import bisect
dir(bisect)
bisect.bisect_left(a, x, lo=0, hi=len(a), *, key=None)

如果 x 已經在 a 裡存在,那麼插入點會在已存在元素之前(也就是左邊)。

左半邊 all(val < x for val in a[lo : i])
右半邊 all(val >= x for val in a[i : hi])

bisect.bisect_right(a, x, lo=0, hi=len(a), *, key=None)
bisect.bisect(a, x, lo=0, hi=len(a), *, key=None)

返回的插入點是 a 中已存在元素 x 的右側。

左半邊 all(val <= x for val in a[lo : i])
右半邊 all(val > x for val in a[i : hi])

bisect.insort_left(a, x, lo=0, hi=len(a), *, key=None)

按照已排序順序將 x 插入到 a 中。

此函數首先會運行 bisect_left() 來定位一個插入點。 然後,它會在 a 上運行 insert() 方法在正確的位置插入 x 以保持排序順序。

bisect.insort_right(a, x, lo=0, hi=len(a), *, key=None)
bisect.insort(a, x, lo=0, hi=len(a), *, key=None)

把 x 插入到 a 中已存在元素 x 的右側。

在 a 上運行 insert() 方法在正確的位置插入 x 以保持排序順序。

To support inserting records in a table, the key function (if any) is applied to x for the search step but not for the insertion step.

key specifies a key function of one argument that is used to extract a comparison key from each element in the array. To support searching complex records, the key function is not applied to the x value.

If key is None, the elements are compared directly with no intervening function call.

二分法對於搜索一定范圍的值是很高效的。 對於定位特定的值,則字典的性能更好。

注意,使用 bisect 模塊的方法之前,要求操作對象是 有序序列(升、降)。
在序列 a 中二分查找適合元素 x 插入的位置,保證 a 仍為有序序列。
lo 和 hi 為可選參數,分別定義查找范圍/返回索引的 上限和下限,缺省時默認對 整個 序列查找。
因此,返回的位置索引 又稱為 “插入點”,將其設為 i,則序列 a 可以被劃分為兩部分,切片表示左側 a[lo, i) 和右側 a[i, hi] 。

Python bisect 源碼

"""Bisection algorithms."""
def insort_right(a, x, lo=0, hi=None, *, key=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. """
if key is None: lo = bisect_right(a, x, lo, hi)
else: lo = bisect_right(a, key(x), lo, hi, key=key)
a.insert(lo, x)
def bisect_right(a, x, lo=0, hi=None, *, key=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(i, 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)
# Note, the comparison uses ">" to match the
# __lt__() logic in list.sort() and in heapq.
if key is None:
while lo < hi:
mid = (lo + hi) // 2
if a[mid] > x: hi = mid
else: lo = mid + 1
else:
while lo < hi:
mid = (lo + hi) // 2
if key(a[mid]) > x: hi = mid
else: lo = mid + 1
return lo
def insort_left(a, x, lo=0, hi=None, *, key=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 key is None: lo = bisect_left(a, x, lo, hi)
else: lo = bisect_left(a, key(x), lo, hi, key=key)
a.insert(lo, x)
def bisect_left(a, x, lo=0, hi=None, *, key=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(i, 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)
# Note, the comparison uses "<" to match the
# __lt__() logic in list.sort() and in heapq.
if key is None:
while lo < hi:
mid = (lo + hi) // 2
if a[mid] < x: lo = mid + 1
else: hi = mid
else:
while lo < hi:
mid = (lo + hi) // 2
if key(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

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved