典型的二分,题目中重点是查找指定数x首次和最后一次出现的位置,以及怎样表示不存在该元素。
一. 查找指定数x首次和最后一次出现的位置
二分基本步骤都懂,那么如何用二分实现该题的查找?
以查找最后一次出现的位置为例:
以该元素为界,则红色部分为小于等于x的部分,绿色部分为大于x的部分,则x位于红色部分的最后一个,即左区间的右边界,通过不断二分使区间中只剩一个数时,这个数为最后一个x。
int l = 0, r = n - 1;
while (l < r) {
int mid = l + r + 1 >> 1;//+1很重要,否则会死循环
if (q[mid] <= x) l = mid;
else r = mid - 1;
}
cout << l << endl;
查找第一个x亦然:
int l = 0, r = n - 1;
while (l < r) {
int mid = l + r >> 1;
if (q[mid] >= x) r = mid;
else l = mid + 1;
}
二.怎样表示不存在该元素
在区间内二分不到该元素,不是没有返回值,而是二分到的不是该元素。当查找首位x时,返回的是第一个大于x的数,故而通过该点判断即可。
if (q[l] != x) cout << "-1 -1" << endl;
三.完整代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e+5;
int n, k;
int q[N];
int main() {
scanf("%d%d", &n, &k);
for (int i = 0; i < n; i++) scanf("%d", &q[i]);
while (k--) {
int x;
scanf("%d", &x);
int l = 0, r = n - 1;
while (l < r) {
int mid = l + r >> 1;
if (q[mid] >= x) r = mid;
else l = mid + 1;
}
if (q[l] != x) cout << "-1 -1" << endl;
else {
cout << l << " ";
int l = 0, r = n - 1;
while (l < r) {
int mid = l + r + 1 >> 1;
if (q[mid] <= x) l = mid;
else r = mid - 1;
}
cout << l << endl;
}
}
return 0;
}