二分查找我觉得是个我特别容易出错的方法,我至少自己笔记都写过很多次,但是每次刷题还是会忘了细节,所以再推一次石头,再写一篇笔记
从性质的角度来理解二分
如果一个数组可以被某个性质分成两部分,其中一部分符合这个性质,另一部分不符合这个性质,则这个数组是可以二分的。以前很喜欢说的一个事情是如果数组单调则可以二分,但是我觉得可能这个更本质的,就是一个性质可以把数组严格分成两类,这其中当然可以有单调,但是也可以有其他性质。
进一步,我们思考这个性质,自然就分成了两类,第一种情况是数组的前半部分符合性质,第二种是数组的后半部分符合性质。而二分的目标也就对应划分成了以下两种:
- 在符合性质的后半段里,找到第一个符合性质的元素
- 在符合性质的前半段里,找到最后一个符合性质的元素
我是觉得从这个角度来理解二分还挺容易的,至少对我来说吧
对应的二分查找模板
性质为准,中心逆边,命中顺边,终点在左:先考虑我们要的性质在左边还是右边,对应的中心选取的时候要选择相逆的那一边(是向上取值还是向下取整),如果中心命中了性质则顺边的指标移动,循环结束以后左指针的位置就是我们要的答案
性质在前面
|
|
性质在后面
|
|
LC4 寻找两个正序数组的中位数
这题是真的难,最后实现的时候用的是二分,但是没有用我们的板子,它的核心是这样,定义一个函数,这个函数返回的是两个数组中第k小的元素,然后我们的中位数其实就是第(n+m)/2小的元素,所以我们可以二分这个k,然后找到这个k,然后返回
进一步,我们如何去实现这个函数呢?
- 我们先规定顺序,要求第一个数组剩余的长度要是小于第二个数组的,否则逆向
- 如果第一个数组搜完了,那第二个数组直接按序即可
- 如果
k==1
,那么我们只需要比较两个数组的第一个元素,然后返回较小的那个 - 如果
k>1
,那么我们就可以二分这个k
,我们先往前走k/2
步,然后比较两个数组中第k/2
小的元素,如果第一个数组中的元素小,那么我们就排除第一个数组的前k/2
个元素,否则就排除第二个数组的前k/2
个元素,然后递归
|
|
LC34 在排序数组中查找元素的首尾位置
这题就很有趣,它要求我们找到元素的第一个和最后一个位置,与此同时它给的数组是排序的,所以我们可以用二分来找到第一个位置和最后一个位置
- 找第一个匹配位置,就是找第一个大于等于target的元素,这里相当于是性质在后面
- 找最后一个匹配位置,就是找最后一个小于等于target的元素,这里相当于是性质在前面
|
|