首页 二分查找
文章
取消

二分查找

二分查找是一个很经典和常用的查找算法,作用在一个有序序列中。其基本思想是 “夹逼”或者“排除”。

查找元素位置

https://leetcode-cn.com/problems/search-insert-position/

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。你可以假设数组中无重复元素。 示例 1: 输入: [1,3,5,6], 5 输出: 2

示例 2: 输入: [1,3,5,6], 2 输出: 1

示例 3: 输入: [1,3,5,6], 7 输出: 4

示例 4: 输入: [1,3,5,6], 0 输出: 0

这个问题是在传统二分法问题上增加了查找目标值不存在的情况下,按序插入的位置。

解法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def find_position(nums: list, target: int):
    if not nums:
        # 空的,返回首位
        return 0
    left = 0                          # 第一位
    right = len(nums) - 1        # 最后一位
    while left < right:
        mid = (left + right) // 2 # 中间一位
        if target < nums[mid]:   # 目标值比中间值小,往左收缩范围
            right = mid
        elif target > nums[mid]: # 目标值比中间值大,往右收缩范围
            left = mid + 1         # 目标值一定是大于中间值的数
        else:                           # 正好找到,返回
            return mid
    return left                        # 没有找到,要插入的位置即是 left


if __name__ == '__main__':
    data = [1, 3, 5, 6, 7, 9, 12]
    print(find_position(nums=data, target=3))  # 1
    print(find_position(nums=data, target=10))  # 6
    print(find_position(nums=[], target=10))  # 0

上面的解法也可以修改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def find_position(nums: list, target: int):
    if not nums:
        return 0
    left = 0
    right = len(nums)   # 若 target 比 nums 中的所有元素都大时,应该返回最后一个元素索引+1,即 len(nums)
    while left < right:
        mid = (left + right) >> 1  # 整除2
        if target > nums[mid]:      # 目标值大于 mid 的话,往右缩小范围
            left = mid + 1
        else:                             # 否则往左缩小范围
            right = mid
    return left


if __name__ == '__main__':
    data = [1, 3, 5, 6, 7, 9, 12]
    print(find_position(nums=data, target=3))  # 1
    print(find_position(nums=data, target=10))  # 6
    print(find_position(nums=[], target=10))  # 0

求平方根

https://leetcode-cn.com/problems/sqrtx/

实现 int sqrt(int x) 函数。 计算并返回 x 的平方根,其中 x 是非负整数。 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 示例 1: 输入: 4 输出: 2

示例 2: 输入: 8 输出: 2

说明: 8 的平方根是 2.82842…, 由于返回类型是整数,小数部分将被舍去。

解法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def cal_floor_sqrt(num):
    if num < 0:
        return
    left = 0
    right = num
    while left < right:
        mid = (left + right + 1) >> 1
        if mid ** 2 > num:
            right = mid - 1         # 结果小于 mid,往左缩小范围
        else:
            left = mid               # 结果大于等于mid,往右缩小范围
    return left


if __name__ == '__main__':
    print(cal_floor_sqrt(1))    # 1
    print(cal_floor_sqrt(2))    # 1
    print(cal_floor_sqrt(3))    # 1
    print(cal_floor_sqrt(4))    # 2
    print(cal_floor_sqrt(5))    # 2

延伸

夹逼的思想运用:https://uphie.studio/posts/查找满足两数之和为指定值的元素下标

本文由作者按照 CC BY 4.0 进行授权