二分算法看似理解十分简单,但是处理边界问题时很容易出错!
这里首先是acwing站主给出的模版,他把二分算法分为了两种情况,但这两个模板对于新手来说较为难以理解和记忆。
bool check(int x) {/* ... */} // 检查x是否满足某种性质
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid; // check()判断mid是否满足性质
else l = mid + 1;
}
return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
链接:https://www.acwing.com/blog/content/277/
通过搜集各种资料,我在b站上找到了一种简单通俗的写法。
原视频在这↓↓↓
步骤:
-
根据题目,确定红蓝分界线,观察两边的性质
-
根据性质来写is_Blue()函数
-
根据具体情况选择返回的是l还是r
#include<iostream>
using namespace std;
int n;
const int N=10010;
bool is_Blue1(int num,int t){
if(num<t) return true;
else return false;
}
int main(){
int a[N],t;//t为要找的目标
cin>>n>>t;
for(int i=0;i<n;i++){
cin>>a[i];
}
//模板
int l=-1,r=n;
while(l+1!=r){
int mid=(l+r)/2;
if(is_Blue1(a[mid],t)){
l=mid;
}else{
r=mid;
}
}
//结合实际问题选择返回的是l还是r
if(a[r]==t) cout<<r<<endl;
else cout<<-1<<endl;
return 0;
}