789. 数的范围
输入样例:
6 3
1 2 2 3 3 4
3
4
5
输出样例:
3 4
5 5
-1 -1
代码:
#include <algorithm> //STL通用算法
#include <bitset> //STL位集容器
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex> //复数类
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque> //STL双端队列容器
#include <exception> //异常处理类
#include <fstream>
#include <functional> //STL定义运算函数(代替运算符)
#include <limits>
#include <list> //STL线性列表容器
#include <map> //STL 映射容器
#include <iomanip>
#include <ios> //基本输入/输出支持
#include<iosfwd> //输入/输出系统使用的前置声明
#include <iostream>
#include <istream> //基本输入流
#include <ostream> //基本输出流
#include <queue> //STL队列容器
#include <set> //STL 集合容器
#include <sstream> //基于字符串的流
#include <stack> //STL堆栈容器
#include <stdexcept> //标准异常类
#include <streambuf> //底层输入/输出支持
#include <string> //字符串类
#include <utility> //STL通用模板类
#include <vector> //STL动态数组容器
#include <cwchar>
#include <cwctype>
using namespace std;
const int N = 1000100;
int a[N];
int m, i, n, j, k, l, q, r;
int main() {
cin >> n >> q;
for (i = 0; i < n; i++) {
cin >> a[i];
}
while (q--) {
cin >> k;
int l = 0, r = n - 1;
while (l < r) {
int mid = l + r >> 1;
if (a[mid] >= k)
r = mid;
else
l = mid + 1;
}
if (a[l] != k)
cout << "-1 -1" << endl;
else {
cout << l << ' ';
int l = 0, r = n - 1;
while (l < r) {
int mid = l + r + 1 >> 1;
if (k >= a[mid])
l = mid;
else
r = mid - 1;
}
cout << l << endl;
}
}
return 0;
}
二分的第一种类型是整数的二分查找
我们把一段范围化成两个区间,即两种情况:
注意,整数二分端点是不重合的
按照本题思路我们先找左边第一个出现的目标值的位置。若a[mid] >= k时,即如图所示:
即更改右边界,因为条件为大于等于,故可能取到a[mid],所以r=mid,反之l=mid+1。
如果第一个目标值都没找到,那直接输出-1 -1,若找到了,输出第一个位置l,并继续找第二个位置下标。
*首先我们要注意到一种情况就是这个数只出现一次,即要输的两个下标相同,此情况下l==r,若再用寻找第一个目标值的方法 mid=l+r>>1 , l==l,那么会出现死循环,即下一次判断条件时需要更新l=mid的值的时候没有改变,那么我们必须让l的值指向下一个位置即l+1,所以mid的处理方法为 mid=l+r+1>>1 ,所得的值即为l+1。