二分
基本思路
建议排列之后再使用,每次找取中间值,若中间值大于我想要的,直接把右边的丢掉;若中间值小于我想要的,那就把左边的丢掉。
具体步骤
1.建议排列之后再使用,设置一个l,一个r分别为左右边界;
2.若mid = (l + r) / 2,用于寻找数组中第一个满足条件的数字,则check(mid),即所求条件与mid的大小关系,若mid大,则让r = mid,丢掉右边的所有数字;若mid小,则让l = mid + 1,不然当数组只剩下两个时会无限循环,丢掉左边的数字;
3.若mid = (l + r + 1 ) / 2,则用于寻找数组中最后一个满足条件的数字,则check(mid)即所求条件与mid的大小关系,若mid大,则让r = mid - 1,不然当数组只剩下两个时会无限循环,丢掉右边的所有数字;若mid小,则让l = mid,丢掉左边的数字;
代码模板
寻找数组中第一个满足条件的数字
int l = 0 , r = n - 1;
while(l < r)
{
int mid = (l + r) >> 1;
if(check(mid))
{
r = mid;
}
else
{
l = mid + 1;
}
}
寻找数组中最后一个满足条件的数字
int l = 0 , r = n - 1;
while(l < r)
{
int mid = (l + r + 1) >> 1;
if(check(mid))
{
l = mid;
}
else
{
r = mid - 1;
}
}
例题
题目链接https://www.acwing.com/problem/content/791/
题解
#include<bits/stdc++.h>
using namespace std;
int n , q;
int arr[100005];
int main()
{
cin >> n >> q;
for(int i = 0 ; i < n ; i++)
{
cin >> arr[i];
}
while(q--)
{
int x;
cin >> x;
int l = 0 ;
int r = n - 1;
while(l < r)//直到l = r时停下,返回一个下标
{
int mid = l + r >> 1;//找最低位直接相加除以二
if(arr[mid] >= x)//最低位先动r
{
r = mid;
}
else
{
l = mid + 1;//l要多加一位
}
}
if(arr[l] != x)
{
cout << "-1 -1" << endl;
}
else
{
cout << l << ' ';//l等于r,任意一个都行
l = 0 , r = n - 1;//再来一次
while(l < r)
{
int mid = (l + r + 1) >> 1;//找最高位要多加一个1,防止tle
if(arr[mid] <= x)
{
l = mid;//最高位从左边开始缩减
}
else
{
r = mid - 1;
}
}
cout << l << endl;
}
}
return 0;
}
浮点数二分
思路
思想一样,不过浮点数中值非常严格,因此几乎不用再取,比较简单;
例题
链接https://www.acwing.com/problem/content/792/
给定一个浮点数 n,求它的三次方根
题解
#include<bits/stdc++.h>
using namespace std;
double n , l , r , mid;
double c_3(double x)
{
return x*x*x;
}
int main()
{
cin >> n;
l = -10000 , r = 10000;
while(r - l >= 1e-7)
{
mid = (l + r) / 2;
if(c_3(mid) >= n)
{
r = mid;
}
else
{
l = mid;
}
}
cout << fixed << setprecision(6) << l;
return 0;
}

浙公网安备 33010602011771号