二分查找(Python)

寻找一个数

def binarysearch(nums, target):
    n = len(nums)
    if n == 0:
        return -1
    left = 0
    right = n - 1
    while left <= right:
        mid = (left + right) // 2
        if target == nums[mid]:
            return mid
        elif target > nums[mid]:
            left = mid + 1
        else:
            right = mid - 1
    return -1

寻找左侧边界

搜索区间:[left, right]

使右边界一直收敛到所找target的左侧边界之前,而结束条件是left==right+1,因此返回left的值

left有可能大于len(nums)-1,但不会小于0

def _find_left_bound(nums, target):
    """
    寻找target的左边界
    """
    left, right = 0, len(nums) - 1
    while left <= right:
        mid = (left + right) // 2
        if nums[mid] < target:
            left = mid + 1
        else:
            # target <= nums[mid]
            right = mid - 1
    # nums[left]以左的元素全部小于target,nums[right]以右的元素全部大于或等于target
    # 终止时 left = right + 1,易知此时left就是target的左边界
    # 由于right的最大值能取到len(nums)-1,因此left有可能超过len(nums)-1,但left不可能小于0
    # target还可能在nums中不存在
    if left < len(nums) - 1 and nums[left] == target:
        return left
    else:
        return -1

实验结果:

>> leftbound([1, 2, 2, 3, 5, 7, 9], 2)
>> result = 1 left = 1

当target不存在,left为首个比target大的值
>> leftbound([1, 3, 5, 7, 9], 2)
>> result = -1 left = 1

当target小于数组最小值,left为0
>> leftbound([1, 3, 5, 7, 9], 0)
>> result = -1 left = 0

当target大于数组最小值,left为len(nums)
>> leftbound([1, 3, 5, 7, 9], 10)
>> result = -1 left = 5

寻找右侧边界

def _find_right_bound(nums, target):
    """
    寻找target的右边界
    """
    left, right = 0, len(nums) - 1
    while left <= right:
        mid = (left + right) // 2
        if target < nums[mid]:
            right = mid - 1
        else:
            # nums[mid] <= target
            left = mid + 1
    # nums[right]以右的元素全部大于target,nums[left]以左的元素全部小于或等于target
    # 终止时 left = right + 1,易知此时right就是target的右边界
    # 由于left的最小值能取到0,因此right有可能小于0,但不可能超过len(nums)-1
    if right >= 0 and nums[right] == target:
        return right
    else:
        return -1

寻找左右边界问题的本质是找到一个位置,使所有小于target的值(且仅有这些值)都在左边(找左边界),或者所有大于target的值(且仅有这些值)都在右边(找右边界)

时间复杂度O(logn)

相当于从一颗二叉搜索树的根走到叶子节点,二叉搜索树的高度为O(logn),因此时间复杂度为O(logn)

空间复杂度O(1)

posted @ 2020-12-01 16:37  luozx207  阅读(137)  评论(0编辑  收藏  举报