个人笔记07

106 阅读3分钟

方向一个人笔记07:二分查找

对于一个下标从0开始、长度为n的有序序列,二分查找算法能在O(logn)的时间复杂度下目标值。此类问题在实践中需要注意的是具体写法的选择,确保不出现非法下标。

二分查找有闭区间、左闭右开区间和开区间三种写法。现在,以找到序列中大于等于目标值target的最小值索引为例,说明不同情况下的写法。

(1)闭区间

初始时设定左、右边界分别为0和n-1。中间索引为左、右边界均值向下取整。

若中间索引对应的值小于目标值,更新左边界为中间索引+1,否则更新右边界为中间索引-1。只要左边界小于等于右边界,该循环就一直进行。循环结束,返回左边界(或右边界+1)。

(2)左闭右开区间

初始时设定左、右边界分别为0和n。若中间索引对应的值小于目标值,更新左边界为中间索引+1,否则更新右边界为中间索引。只要左边界小于右边界,该循环就一直进行。循环结束,返回左边界(或右边界)。

(3)开区间

初始时设定左、右边界分为-1和n。若中间索引对应的值小于目标值,更新左边界为中间索引,否则更新右边界为中间索引。只要左边界小于右边界-1,该循环就一直进行。循环结束,返回左边界+1(或右边界)。

以上方法的关键都是保证区间不为空,严格按照其中一种写法写完整个程序,可以避免逻辑混乱。

(例题)小R需要在days天内将一批包裹运送到另一个港口。传送带上的每个包裹的重量由数组weights表示。每一天,小R按照包裹在weights中的顺序装载包裹,装载的总重量不会超过船的最大运载能力。为了在规定的天数内完成运输任务,小R希望知道船的最低运载能力是多少,才能确保所有包裹能够在days天内全部送达。

(思路)记weights中的最大值为maxw,weights中所有元素之和为tot。本题实质上是在[maxw,tot]中找到一个可能的最小值,使得总运送天数不超过days。

下面采用闭区间写法,初始时令left=maxw,right=tot。每次循环中,中间值mid为(left+right)//2。计算在mid下运送货物所需天数need:令need初始值为1,用cur记录一次装载的货物量(初始值为0)。因为必须按顺序装载货物,当cur+weights[i]>mid时,need加1,然后cur重置为0。

如果所需天数need小于等于days,更新right为mid-1,否则更新left为mid+1。最终,返回left。

除了常规的查找外,有一类问题可以用二分法解决:

求第k小(大)的值等价于:求最小(最大)的x,满足小于等于(大于等于)x的数至少有k个。这一类问题尤以有序矩阵中的值查找为经典。