【玩转算法】二分搜索

  1. 二分搜索(折半搜索)的 Wikipedia 定义:是一种在有序数组中查找某一特定元素的搜索算法。从定义可知,运用二分搜索的前提是数组必须是排好序的。另外,输入并不一定是数组,也有可能是给定一个区间的起始和终止的位置。算法的难点在边界的处理上。

  2. 优点:时间复杂度是 O(logn),非常高效。因此也称为对数搜索。

  3. 缺点:要求待查找的数组或者区间是排好序的。

  4. 对数组进行动态的删除和插入操作并完成查找,平均复杂度会变为 O(n)。此时应当考虑采取自平衡的二叉查找树:

    1. 在 O(nlogn) 的时间内用给定的数据构建出一棵二叉查找树;
    2. 在 O(logn) 的时间里对目标数据进行搜索;
    3. 在 O(logn) 的时间里完成删除和插入的操作。
  5. 因此,当输入的数组或者区间是排好序的,同时又不会经常变动,而要求从里面找出一个满足条件的元素的时候,二分搜索就是最好的选择。

  6. 二分搜索一般化的解题思路如下:

    1. 从已经排好序的数组或区间中取出中间位置的元素,判断该元素是否满足要搜索的条件,如果满足,停止搜索,程序结束。
    2. 如果正中间的元素不满足条件,则从它两边的区域进行搜索。由于数组是排好序的,可以利用排除法,确定接下来应该从这两个区间中的哪一个去搜索。
    3. 通过判断,如果发现真正要找的元素在左半区间的话,就继续在左半区间里进行二分搜索。反之,就在右半区间里进行二分搜索。
  7. 递归解法,

    1. 优点:简洁;
    2. 缺点:执行消耗大
    3. 代码示例如下:
    # 返回 x 在 arr 中的索引,如果不存在返回 -1
    def binarySearch (arr, l, r, target):  
        # 基本判断
        if r >= l: 
            mid = int(l + (r - l)/2)   //避免整型溢出
            # 元素整好的中间位置
            if arr[mid] == target: 
                return mid          
            # 元素小于中间位置的元素,只需要再比较左边的元素
            elif arr[mid] > target: 
                return binarySearch(arr, l, mid-1, target) 
            # 元素大于中间位置的元素,只需要再比较右边的元素
            else: 
                return binarySearch(arr, mid+1, r, target) 
        else: 
            # 不存在
            return -1
    
    1. 注意:
      1. 在计算 middle 下标的时候,不能简单地用 (low + hight) / 2,可能会导致溢出。
      2. 在取左半边以及右半边的区间时,左半边是 [low, middle - 1],右半边是 [middle + 1, high],这是两个闭区间。因为已经确定了 middle 那个点不是我们要找的,就没有必要再把它加入到左、右半边了。
      3. 对于一个长度为奇数的数组,例如:{1, 2, 3, 4, 5},按照 low + (high - low) / 2 来计算,middle 就是正中间的那个位置,对于一个长度为偶数的数组,例如 {1, 2, 3, 4},middle 就是正中间靠左边的一个位置。
  8. 非递归解法:

    1. 核心步骤:

      1. 确定搜索的范围和区间
      2. 取中间的数判断是否满足条件
      3. 如果不满足条件,判定应该往哪个半边继续进行搜索
    2. 代码示例如下:

      def BinarySearch(arr, l, r, target):
         while l <= r:
              mid = int(l + (r - l)/2)
              if arr[mid] == target:
                  return mid
              if target < arr[mid]:
                  r = mid-1
              else:
                  l = mid+1
          # 不存在
          return -1
      
  9. 二分查找经典例题:

    1. LeetCode 第 33 题:搜索旋转排序数组
    2. LeetCode 第 34 题:在排序数组中查找元素的第一个和最后一个位置
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值