2.1 整数二分
AcWing 789 数的范围
题目描述(以题带点 --)
给定一个按照升序排列的长度为 n 的整数数组,以及 q 个查询。
对于每个查询,返回一个元素 k 的起始位置和终止位置(位置从 0 开始计数)。
如果数组中不存在该元素,则返回 -1 -1。
输入格式
第一行包含整数 n 和 q,表示数组长度和询问个数。
第二行包含 n 个整数(均在 1∼10000 范围内),表示完整数组。
接下来 q 行,每行包含一个整数 k,表示一个询问元素。
输出格式
共 q 行,每行包含两个整数,表示所求元素的起始位置和终止位置。
如果数组中不存在该元素,则返回 -1 -1。
数据范围
1≤n≤100000
1≤q≤10000
1≤k≤10000
输入样例
6 3
1 2 2 3 3 4
3
4
5
输入样例
3 4
5 5
-1 -1
#include<bits/stdc++.h> //万能头-yyds
using namespace std;
const int N = 1e5 + 10; //n的范围(题干给的)
int n, q;
int a[N];
int l_find(int& ta) //找起始位置的函数 (建议先看main函数)
{
int l = 0, r = n - 1, m; //定义一堆变量(眼花缭乱)
// l(不是数字1,是字母l“爱咯“) 是二分查找的左边界,r是右边界 ,你猜m是什么
while (l <= r)
{
m = l + r >> 1; // m = (l+r)/2
if (a[m] >= ta) r = m - 1; //如果数列中间那个值大于等于要找的目标值,把右边界提过来 二分查找的精髓
else
l = m + 1; //否则就把左边界踢过去
}
if (l >= n || a[l] != ta)
return -1; //如果到最后还没有找到该元素 输出-1
return l; //把l 弹出
}
int r_find(int& ta) //找终止位置的函数 (建议先看main函数)
{
int l = 0, r = n - 1, m;
while(l<=r)
{
m = l + r >> 1;
if (a[m] <= ta) l = m + 1;
else r = m - 1;
}
if (r < 0 || a[r] != ta)
return -1;
return r;
//一句“同理可得”不过分吧
}
int main()
{
ios::sync_with_stdio(false); //加速cin cout 不必纠结,套用就好
cin.tie(0);
cout.tie(0);
int i;
cin >> n >> q;
for (i = 0; i < n; ++i)
{
cin >> a[i];
}
while (q--)
{
cin >> i;
cout << l_find(i) << " " << r_find(i) << endl;
}
}
总结
二分法查找,概括来说,就是对于一段有序的数列,每次找到中间位置的值,通过与目标值比较过后确定目标值的区间,然后通过循环语句不断缩小区间,最后把目标值“夹”出来