-
二分搜索(折半搜索)的 Wikipedia 定义:是一种在有序数组中查找某一特定元素的搜索算法。从定义可知,运用二分搜索的前提是数组必须是排好序的。另外,输入并不一定是数组,也有可能是给定一个区间的起始和终止的位置。算法的难点在边界的处理上。
-
优点:时间复杂度是 O(logn),非常高效。因此也称为对数搜索。
-
缺点:要求待查找的数组或者区间是排好序的。
-
对数组进行动态的删除和插入操作并完成查找,平均复杂度会变为 O(n)。此时应当考虑采取自平衡的二叉查找树:
- 在 O(nlogn) 的时间内用给定的数据构建出一棵二叉查找树;
- 在 O(logn) 的时间里对目标数据进行搜索;
- 在 O(logn) 的时间里完成删除和插入的操作。
-
因此,当输入的数组或者区间是排好序的,同时又不会经常变动,而要求从里面找出一个满足条件的元素的时候,二分搜索就是最好的选择。
-
二分搜索一般化的解题思路如下:
- 从已经排好序的数组或区间中取出中间位置的元素,判断该元素是否满足要搜索的条件,如果满足,停止搜索,程序结束。
- 如果正中间的元素不满足条件,则从它两边的区域进行搜索。由于数组是排好序的,可以利用排除法,确定接下来应该从这两个区间中的哪一个去搜索。
- 通过判断,如果发现真正要找的元素在左半区间的话,就继续在左半区间里进行二分搜索。反之,就在右半区间里进行二分搜索。
-
递归解法,
- 优点:简洁;
- 缺点:执行消耗大
- 代码示例如下:
# 返回 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
- 注意:
- 在计算 middle 下标的时候,不能简单地用 (low + hight) / 2,可能会导致溢出。
- 在取左半边以及右半边的区间时,左半边是 [low, middle - 1],右半边是 [middle + 1, high],这是两个闭区间。因为已经确定了 middle 那个点不是我们要找的,就没有必要再把它加入到左、右半边了。
- 对于一个长度为奇数的数组,例如:{1, 2, 3, 4, 5},按照 low + (high - low) / 2 来计算,middle 就是正中间的那个位置,对于一个长度为偶数的数组,例如 {1, 2, 3, 4},middle 就是正中间靠左边的一个位置。
-
非递归解法:
-
核心步骤:
- 确定搜索的范围和区间
- 取中间的数判断是否满足条件
- 如果不满足条件,判定应该往哪个半边继续进行搜索
-
代码示例如下:
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
-
-
二分查找经典例题:
- LeetCode 第 33 题:搜索旋转排序数组
- LeetCode 第 34 题:在排序数组中查找元素的第一个和最后一个位置
【玩转算法】二分搜索
最新推荐文章于 2021-07-22 10:58:19 发布