青训营X豆包

106 阅读3分钟

青训营 二分查找一般解法 特例题解 | 豆包MarsCode AI刷题

案例引入

在有序数组中,查找某一特定元素时可以使用二分查找,以O(log n)的时间复杂度优于正常O(n)遍历。

而在今天刷题遇到的满足某一特定公式最小值便能使用,本体使用python进行解答。

题目描述:

image.png

题目初步分析:

本题给出两个数组和一个整数k值,需要从两个数组中各选取一个值代入公式中,求能够获得的最小值。如果直接每次都直接遍历整个数组,则时间复杂度会极其高。因此考虑使用二分查找来进行解答。因此对b进行排序,在正常遍历数组a的同时对b进行二分查找,同时计算最小值。

题目详解

  1. 首先将res设置为最大值,每次判断如果比res小则更新res,同时对b进行排序。

    python
     代码解读
    复制代码
    #将结果设置为最大值
    res=sys.maxsize
    #对b数组进行排序
    b.sort()
    
  2. 遍历数列 a:对于数列 a 中的每一个元素,使用二分查找在排序后的数列 b 中找到最接近的 b[j],使得 |(a[i] - b[j])^2 - k^2| 最小

    python
     代码解读
    复制代码
    #遍历a数列 
    for ai in a:
     	#利用python自带的bisect库进行二分查找
        index=bisect_left(b,ai-k)
    
  3. 计算并更新最小值:在遍历过程中,计算并更新最小值

    python
     代码解读
    复制代码
    #找到与ai相近的bj的位置
    candidates = []
    if index < len(b):
    	candidates.append(b[index])
    if index > 0:
        candidates.append(b[index- 1])
                
    # 计算 `|(ai - bj)^2 - k^2|` 的值
    for bj in candidates:
        current_value = abs((ai - bj) ** 2 - k ** 2)
        if current_value < res:
        res = current_value
    
  4. 整体代码如下:

    python
     代码解读
    复制代码
    from bisect import bisect_left
    import sys
    
    def solution(n: int, m: int, k: int, a: list[int], b: list[int]) -> int:
        # Please write your code here
        res=sys.maxsize
        b.sort()
        for ai in a:
            index=bisect_left(b,ai-k)
            candidates = []
            if index < len(b):
                candidates.append(b[index])
            if index > 0:
                candidates.append(b[index- 1])
                
            # 计算 `|(ai - bj)^2 - k^2|` 的值
            for bj in candidates:
                current_value = abs((ai - bj) ** 2 - k ** 2)
                if current_value < res:
                    res = current_value
        return res
    

    运行结果如下: image.png

二分查找一般解法

二分查找(Binary Search)是一种高效的查找算法,适用于在有序数组中查找特定元素。它的基本思想是通过将查找范围逐步缩小一半来快速定位目标元素。

二分查找适用场景:

  • 有序数组:二分查找适用于在有序数组中查找特定元素。
  • 查找插入位置:可以使用二分查找来找到插入新元素的位置,以保持数组有序。
  • 查找边界:可以扩展二分查找来查找数组中某个元素的第一个或最后一个出现位置。

二分查找解题步骤:

  1. 初始化

    • 设定查找范围的左边界 left 和右边界 right
    • 初始时,left 为数组的起始索引(通常为 0),right 为数组的末尾索引(通常为 len(array) - 1)。
  2. 循环查找

    • 在每次循环中,计算中间索引 mid,即 mid = (left + right) // 2

    • 比较中间元素

      c
       代码解读
      复制代码
      array[mid]
      

      与目标元素

       代码解读
      复制代码
      target
      

      • 如果 array[mid] == target,则找到目标元素,返回 mid
      • 如果 array[mid] < target,则目标元素在右半部分,更新 left = mid + 1
      • 如果 array[mid] > target,则目标元素在左半部分,更新 right = mid - 1
  3. 结束条件

    • left 超过 right 时,表示查找范围为空,目标元素不在数组中,返回 -1 或其他表示未找到的值。

总结与思考

在python中有能够直接实现二分查找的常用库bisect如在本题中所使用的bisect_left方法来直接获取某一索引 。在有序数组中:bisect.bisect和bisect.bisect_right返回大于x的第一个下标(相当于C++中的upper_bound),bisect.bisect_left返回大于等于x的第一个下标(相当于C++中的lower_bound)。