[算法系列] - 二分查找法O(logn)

187 阅读1分钟

1. 有序数组中不存在重复元素,用二分查找值等于给定值的数据。

Python代码实现:

from typing import List

def bsearch(a: List[int], target: int) -> int:
    low = 0
    high = len(a) - 1
    while low <= high:
        mid = low + (high - low) // 2
        if a[mid] == target:
            return mid
        elif a[mid] > target:
            high = mid -1
        else:
            low = mid + 1
    return None

三个易错点:

(1). 循环退出条件:

  low<=high,而不是low<high

(2). mid的取值:

  mid = (low + high) // 2  这种写法可能造成溢出

  mid = low + (high - low) // 2  正确写法

  mid = low + ((high - low) >> 1  位运算性能更优

(3). low和high的更新:

  low = mid + 1

  high = mid - 1
  

2. 查找第一个值等于给定值的元素。

Python代码实现:

def bsearch_left(a: List[int], target: int) -> int:
    low = 0
    high = len(a) - 1
    while low <= high:
        mid = low + (high - low) // 2
        if a[mid] > target:
            high = mid -1
        elif a[mid] < target:
            low = mid + 1
        else:
            if mid == 0 or a[mid-1] != target:
                return mid
            else:
                high = mid - 1
    return None

3. 查找最后一个值等于给定值的元素。

Python代码实现:

def bsearch_right(a: List[int], target: int) -> int:
    low = 0
    high = len(a) - 1
    while low <= high:
        mid = low + (high - low) // 2
        if a[mid] > target:
            high = mid -1
        elif a[mid] < target:
            low = mid + 1
        else:
            if mid == len(a)-1 or a[mid+1] != target:
                return mid
            else:
                low = mid + 1
    return None

4. 查找第一个大于等于给定值的元素。

Python代码实现:

def bsearch_left_not_less(a: List[int], target: int) -> int:
    low = 0
    high = len(a) - 1
    while low <= high:
        mid = low + (high - low) // 2
        if a[mid] < target:
            low = mid + 1
        else:
            if mid == 0 or a[mid-1] < target:
                return mid
            else:
                high = mid - 1
    return None

5. 查找最后一个小于等于给定值的元素。

Python代码实现:

def bsearch_right_not_greater(a: List[int], target: int) -> int:
    low = 0
    high = len(a) - 1
    while low <= high:
        mid = low + (high - low) // 2
        if a[mid] > target:
            high = mid -1
        else:
            if mid == len(a)-1 or a[mid+1] > target:
                return mid
            else:
                low = mid + 1
    return None