整数二分
本质:边界,如某种性质在某左/右满足/不满足,寻找其边界点
注意:有单调性一定可以二分,可以二分不一定需要有单调性
类型1
[l,r]--->[l,mid-1]+[mid,r] 左区间的右边界点
①找中间值:mid=(l+r+1)/2
②判断中间值是否满足性质,满足则左(边界在mid-r之间),否则右(边界在l-mid-1之间)
③更新区间:l=mid或r=mid-1
类型2
①找中间值:mid=(l+r)/2
②判断中间值是否满足性质,满足则右(边界在l-mid之间),否则左(边界在mid+1-r之间)
③更新区间:r=mid或l=mid+1
代码示例
题目要求:输入数组长度和问询个数,输入升序数组,输出所问询数字的起始下标和结束下标,否则输出-1
const int N = 100010;
int n, m;
int q[N];
int main()
{
//读入长度和问询个数
scanf("%d%d", &n, &m);
//读入数据
for (int i = 0; i < n; i++)
{
scanf("%d", &q[i]);
}
while (m--)
{
//输入查询对象
int x;
scanf("%d", &x);
//定义边界
int l = 0, r = n - 1;
//找左边界(第一个等于x的数)
while (l < r)
{
//定义中间点
int mid = (l + r) / 2;
//更新边界
if (q[mid] >= x) r = mid;
else l = mid + 1;
}
//如果不存在x,经过上述循环,l和r是相等的,左边界值是一定不等于x的
if (q[l] != x) printf("-1\n");
else
{
printf("%d ", l);
//找右边界(最后一个等于x的数)
//定义边界
int l = 0, r = n - 1;
while (l < r)
{
//定义中间点
int mid = (l + r + 1) / 2;
//更新边界
if (q[mid] <= x) l = mid;
else r = mid - 1;
}
printf("%d ", l);
}
}
return 0;
}
浮点数二分
示例:开平方
int main()
{
//输入数据
double x;
cin >> x;
if(x>=1)
{
//定义区间
double l = 1, r = x;
while (r - l > 1e-8)//至少要比要求的有效位数多2,要求4位就-6,6位就-8
//也可以不用精度控制,可以直接循环100次
{
//不需要考虑边界问题
double mid = (l + r) / 2;
if (mid * mid >= x) r = mid;
else l = mid;
}
printf("%lf\n", l);
}
else
{
double l = x, r = 1;
while (r - l > 1e-8)
{
double mid = (l + r) / 2;
if (mid * mid >= x) r = mid;
else l = mid;
}
printf("%lf\n", l);
}
return 0;
值得注意的是,对于浮点数二分,我们是不需要考虑l和r的边界问题的,即不可以直接将mid赋值给l或r