编程算法之二分法详解(二分不一定要有序)
二分法是一种算法思想。你们可能听过二分查找,其输入是一个有序的元素列表。如果要查找的元素包含在列表中,二分查找返回其位置;否则返回-1,这是最经典的二分法。所以你们可能认为二分法就一定要有序,答案不一定!二分只是一种思想,只要你能找到一个能支撑二分的规则,就可以利用二分法的思路去求解,各种情况的解析,下面会以例子详细解析。
二分法示例:
- 在一个有序数组中,找某个数是否存在
- 在一个有序数组中,找>=某个数最左侧的位置
- 在一个有序数组中,找<=某个数最右侧的位置
- 局部最小值问题(无序二分)
1. 经典的二分法-二分查找
在一个有序数组中,找某个数是否存在。
下面的示例说明了二分查找的工作原理:
我随便想一个1~100的数字。
你的目标是以最少的次数猜到这个数字。你每次猜测后,我会说小了、大了或对了。
-
假设你从1开始依次往上猜,这是简单查找,更准确的说法是傻找。每次猜测都只能排除一个数字。如果我想的数字是99,你得猜99次才能猜到!
-
下面二分的猜法。从50 开始。
-
小了,但排除了一半的数字!至此,你知道1~50都小了。接下来,你猜75。
-
大了,那余下的数字又排除了一半!使用二分查找时,你猜测的是中间的数字,
从而每次都将余下的数字排除一半。接下来,你猜63(50和75中间的数字)。 -
这就是二分查找!每次猜测排除的数字个数如下。
-
100 -> 50 -> 25 -> 13 -> 7 -> 4 -> 2 -> 1 // 7步
-
不管我心里想的是哪个数字,你在7次之内都能猜到,因为每次猜测都将排除很多数字!
-
-
二分查找的代码实现:
function binary_search(arr, item) {
// 对传参进行判断
if (!Array.isArray(arr) || arr.length === 0) {
return -1
}
// L和R用于跟踪要在其中要查找的列表范围
let L = 0
let R = arr.length - 1
// 只要范围没有缩小到只包含一个元素
while (L <= R) {
// 获取范围的中间索引