最后更新于
最后更新于
二分法一般应用在数组上, 在数组中以的时间复杂度进行查找. 首先设置左右端点, 找到中间点, 一般根据(left + right) // 2
找到中间点. 然后根据中间点的值与左右端点值的大小, 以及不同题目中各异的逻辑关系, 将其中的一个端点移动到中间点上或中间点附近, 完成一轮的迭代. 之后重复这个步骤, 直到满足停止条件, 这个条件一般是左右端点汇聚在一个位置时, 或左右端点越界, 左在右侧, 右在左侧, 这个条件也是要根据具体的题目确定. 最终左端点(普遍情况)或右端点所在的位置, 或这个位置对应的值就是最后的答案.
其中由很多细节:
端点移动的细节: 左右端点向中间移动时方案不同; 移动到中间点, 还是中间点邻近的一个位置
终止条件: 左右端点处于同一个端点时停止; 左右交叉后停止
前两者的结合, 终止条件的变化, 很可能就会导致移动细节的变化
其他
一般求新的中点使用公式(left + right) // 2
. 由于使用的是整除, 所以存在 , 即如果left
和right
不相等, 得到的mid
是一定小于右端索引, 不小于左端索引, 但是可能与左端相等, 即mid
就是left
.
这点非常重要. 因为我们设计移动策略的时候, 要保证端点不能原地移动, 否则左右端点经过一轮迭代后没有移动, 求出的中间点还是一样的, 会陷入死循环.
所以在制定左侧端点的移动策略时, 一般在满足特定条件后需要移动左端点时, 会使left = mid + 1
, 以避免最终原地踏步, 陷入死循环. 而右侧端点使得right = mid
即可.
当然能否这样移动, 不同题目还需要进行不同的考虑.
如果是左右端点处于同一个端点时停止, 则循环条件应写为while left < right
; 如果是左右交叉后停止, 循环条件应写为while left <= right
. 在实际题目中设置终止条件时, 可以多考虑以下点.
left == right
按照left = mid + 1
和right = mid
的移动策略, 一轮迭代之后, 满足left == right
, 有两种情况.
要求迭代前left
与right
相邻, 即left = right - 1
, 两者确定的子数组长度为2. mid = (left + right) // 2 = left
, 两者相遇.
根据mid = (left + right) // 2 + 1 = right
, 可以得到此时left = right - 2
, 两者确定的子数组长度为3.
参考.