二分法的精辟干货文章
简单二分 只能针对有序数组
对下面数组无效,但局部有序

针对这个问题的模板
判断条件while (left < right)
模板1 寻找第一个满足XXX的位置:
int left = 0, right = nums.length - 1;
while (left < right) {
int middle = left + (right - left) / 2;
if (满足XXX) {
right = middle;
} else {
left = middle + 1;
}
}
模板2 寻找最后一个满足XXX的位置:
int left = 0, right = nums.length - 1;
while (left < right) {
// +1是为了让相除结果向上取整,这个地方就是两套模板的区别之一
int middle = left + (right - left + 1) / 2;
if (满足XXX) {
left = middle;
} else {
right = middle - 1;
}
}
最终的二分结果,返回left 或 right 都可,因为退出循环时一定有 left==right
假设你只记住了 寻找第一个满足XXX 这个模板,但是遇到的实际需求是 寻找最后一个满足XXX ,你完全可以将二分目标修改为: 寻找第一个不满足XXX 的位置(也就是把 if条件 改成对应相反的,其余都不用动)。可知它的上一个位置就是 最后一个满足XXX 的,所以你把算出来的二分结果减去1,就是答案了。(反之同理,由 最后一个 -> 第一个 是 +1 操作
不过,这样得到的结果,很多时候都需要进行 后判断处理 ,否则会带来问题。
如果你是由 一种情况 转化到 另一种情况 的话,可能会带来 “索引越界” 的问题。这是因为:在结果转化时需要进行 -1(或者 +1) 的操作。假设本身的二分结果是0,然后你减去了1,结果变成-1了,那就下标越界啦!所以在最后返回前,必须判断一下这个下标究竟是否合法(如果题目保证一定存在答案,那么大可放心不必进行这些判断):
// 这里用 -1 表示下标非法时的返回结果
return left >= 0 && left < nums.length ? left : -1;
另外,如果题目不保证一定存在答案,那么即使没有产生 “索引越界” ,也可能得到 “错误答案” 。例如 寻找有序数组中元素值为 target 的元素所在位置,但是并不保证它一定存在 。拿到这题,我设定二分目标是: 寻找第一个满足 nums[i] >= target 的位置 i ,最终我得到的二分结果是 left (也同样是 right ) 。可是我只知道 nums[left] >= target 是没错的,但不见得 nums[left] == target 也一定没错!!因此就必须要后判断处理:
// 这里用 -1 表示数组中不存在 target 的返回结果
return nums[left] == target ? left : -1;
例题:
寻找旋转排序数组中的最小值
寻找峰值
寻找峰值答案:
class Solution {
public:
int findPeakElement(vector<int>& nums) {
int l = 0, r = nums.size() - 1;
while(l < r)
{
int mid = (l + r) >> 1;
if(nums[mid] >= nums[mid + 1])
{
r = mid;
}
else
{
l = mid + 1;
}
}
return l;
}
};
2892

被折叠的 条评论
为什么被折叠?



