<—点个赞吧QwQ
宣传一下算法基础课整理{:target=”_blank”}
给定一个按照升序排列的长度为 $n$ 的整数数组,以及 $q$ 个查询。
对于每个查询,返回一个元素 $k$ 的起始位置和终止位置(位置从 $0$ 开始计数)。
如果数组中不存在该元素,则返回 -1 -1
。
输入格式
第一行包含整数 $n$ 和 $q$,表示数组长度和询问个数。
第二行包含 $n$ 个整数(均在 $1 \\sim 10000$ 范围内),表示完整数组。
接下来 $q$ 行,每行包含一个整数 $k$,表示一个询问元素。
输出格式
共 $q$ 行,每行包含两个整数,表示所求元素的起始位置和终止位置。
如果数组中不存在该元素,则返回 -1 -1
。
数据范围
$1 \\le n \\le 100000$
$1 \\le q \\le 10000$
$1 \\le k \\le 10000$
输入样例:
6 3
1 2 2 3 3 4
3
4
5
输出样例:
3 4
5 5
-1 -1
思路1
$STL$大法好!!!
代码1
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int n,m;
int a[N];
int main () {
cin >> n >> m;
for (int i = 0;i < n;i++) cin >> a[i];
while (m--) {
int x;
cin >> x;
int t = lower_bound (a,a + n,x) - a;
if (a[t] != x) {
puts ("-1 -1");
continue;
}
else cout << t << ' ' << upper_bound (a + 1,a + 1 + n,x) - a - 1 << endl;
//这里upper_bound要-1,因为他是指着不符合条件的第一个数!!
}
return 0;
}
思路2
请见二分答案详解
代码2
#include <iostream>
using namespace std;
const int N = 100010;
int n,m;
int a[N];
int main () {
cin >> n >> m;
for (int i = 1;i <= n;i++) cin >> a[i];
while (m--) {
int x;
cin >> x;
int l = 1,r = n;
while (l < r) {
int mid = l + r >> 1;
if (a[mid] < x) l = mid + 1; //如果当前点不符合要求,就l=mid+1,因为mid是不合法的,就跳过
else r = mid; //对应的模板
}
if (a[l] != x) {
puts ("-1 -1");
continue;
}
else cout << l - 1 << ' ';
l = 1,r = n;
while (l < r) {
int mid = l + r + 1 >> 1; //这里+1可以写完了模板再加上
if (a[mid] <= x) l = mid; //如果当前点是合法的,mid可能是答案,不能跳过l=mid
else r = mid - 1; //对应的模板
}
cout << l - 1 << endl;
}
return 0;
}
倒数几行这里— if (a[mid] <= x) l = mid; 这里如果mid前面也有好几个x值是不是会跳过呢?所以我觉得遇到a[mid]==x的情况就老老实实分类讨论好了,如果两边界也都等于x,那么最好了直接return{l,r};否则哪边不等于x就让哪边++,这样一定不会跳过任何一个x值。