“ Ctrl AC!一起 AC!”
目录
前言:
二分算法的模板多到有点恐怖,但它们基本都只是实现了两种算法:所有解中找最大优解、所有解中找最小优解。(那我(们)干脆每种记一个模板就够了,鄙人很懒,你们随意咯)。
至于二分算法的模板为什么有很多,那是因为
1.退出循环的选while(l<r) 还是选 while(l<=r) 。
2. 什么时候用 l=mid,l=mid-1,l-mid+1,r=mid,r=mid+1,r=mid-1里面的哪两个组合。
3. 答案是mid 还是 r 还是 l。
其实熟悉二分的同学可以直接推理出来,就不需要固定的模板。那么对于刚入门的同学可以背背模板,慢慢熟悉。
模板一:找最大优解
int l = 0, r = len - 1, int mid;
while (l < r) {
mid = (l + r + 1) / 2; //+1不理解可自己模拟一遍 或评论区见
if (check(mid)) l = mid; //mid可以就往右走,找更大的值,范围变为[mid,r]
else r = mid - 1; //mid不行就往左走,范围变为[l,mid-1]
}
int ans = l || r;
模板二:找最小优解
int l = 0, r = len - 1, int mid;
while (l < r) {
mid = (l + r) / 2;
if (check(mid)) r = mid; //mid可以就往左走,找更小的值,范围变为[l,mid]
else l = mid + 1; //mid不行就往右走,范围变为[mid+1,r]
}
int ans = l || r;
实例一:(模一套用)
题目: 查找插入位置
分析:这题想要套用模板一的话,就要找比target小的数里面的最大值,然后下标加一。但是这里有特殊情况,就是如果没有比target小的数的话,就要返回0。
AC代码:
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int len=nums.size();
int l=0,r=len-1;
//模板一套用
while(l<r){
int mid=(l+r+1)/2;
if(nums[mid]<target) l=mid;
else r=mid-1;
}
if(l==0&&nums[l]>=target) return 0; //判断特殊情况
return l+1;
}
};
实例二:(模二套用)
题目:公平的糖果交换
分析:这道题首先找出两人糖果总数差,再除二 设为change,遍历第一个人的每盒糖果。
设delt=num1[i]-change, 我们只需在第二个人的数组num2中找有没有delt就行。
交换这两盒,就能达到目的。套用模板二后需要判断条件。
AC代码:
class Solution {
public:
vector<int> fairCandySwap(vector<int>& aliceSizes, vector<int>& bobSizes) {
vector<int> answer;
int len1=aliceSizes.size();
int len2=bobSizes.size();
int sum1=0,sum2=0;
for(int i=0;i<len1;i++){
sum1+=aliceSizes[i];
}
for(int j=0;j<len2;j++){
sum2+=bobSizes[j];
}
int change=(sum1-sum2)/2;
sort(bobSizes.begin(),bobSizes.end());//二分前提:排序
for(int i=0;i<len1;i++){
int delt=aliceSizes[i]-change;
int l=0,r=len2-1;
//套用模板二
while(l<r){
int mid=(l+r)/2;
if(bobSizes[mid]<delt) l=mid+1;
else r=mid;
}
//因为可能根本找不到delt,所以要判断
if(bobSizes[l]==delt){
answer.push_back(aliceSizes[i]);
answer.push_back(bobSizes[l]);
break;
}
}
return answer;
}
};
更多模板见:
感谢阅读!!!
“ Ctrl AC!一起 AC!”