二分难点
二分的主要难点在于两个:
- 找到一个单调的序列
- 确定需要搜索的目标,并且确定使用怎样的条件去缩小范围
- 边界条件与题目所求是否对应(确定返回值的含义)
第一个主要是证明,因为有的题不是直接给一个序列让你搜索,像母题一样,而是藏在更深的地方。所以这个要视情况而定
第三个参考https://leetcode.cn/problems/maximum-value-at-a-given-index-in-a-bounded-array/solution/by-lao-song-2f-n5b6/
模板
概括为一共有两个模板:
- 搜索大于target的第一个元素 =====》 upper_bound()
int l = 0, r = nums.size()-1;
while(l<=r){
int mid = (l+r)/2;
if(nums[mid]>target) r = mid-1;
else l = mid+1;
}
return l; //代表第一个大于target的下标
- 搜索大于等于target的第一个元素 =====》lower_bound()
int l = 0, r = nums.size()-1;
while(l<=r){
int mid = (l+r)/2;
if(nums[mid]>=target) r = mid-1;
else l = mid+1;
}
return l; //代表第一个大于等于target的下标
两者的区别主要就是if后面的判断语句有没有等号。思考方式是,while循环跳出的情况只可能是跳出前lrmid,此时若nums[mid]>=target,则r=mid-1,此时l就大于r了,下一次就进不了while了。但关键在于l没变位置(还是l==r时的位置),那么当时的情况是nums[mid]>=target,说明l(==mid)是使得nums[l]大于等于目标值的第一个下标。else里的情况也是一样思考,得出的结论相同。
其他
灵活运用这两个模板才是关键
举个例子:当题目要求重复元素中的第一个时,使用第二个模板,此时;当题目要求重复元素的最后一个时,使用第一个模板;
当题目要求 求小于target的最后一个元素时,那么反过来其实就是求大于等于target的第一个元素,那么用第二个模板求出的l-1就可以了。