给定一个按照升序排列的长度为 nn 的整数数组,以及 qq 个查询。
对于每个查询,返回一个元素 kk 的起始位置和终止位置(位置从 00 开始计数)。
如果数组中不存在该元素,则返回 -1 -1
。
输入格式
第一行包含整数 nn 和 qq,表示数组长度和询问个数。
第二行包含 nn 个整数(均在 1∼100001∼10000 范围内),表示完整数组。
接下来 qq 行,每行包含一个整数 kk,表示一个询问元素。
输出格式
共 qq 行,每行包含两个整数,表示所求元素的起始位置和终止位置。
如果数组中不存在该元素,则返回 -1 -1
。
数据范围
1≤n≤1000001≤n≤100000
1≤q≤100001≤q≤10000
1≤k≤100001≤k≤10000
输入样例:
6 3
1 2 2 3 3 4
3
4
5
输出样例:
3 4
5 5
-1 -1
本题目通过二分算法找出左边界与右边界,最后输出左边界与右边的的值即可。
二分的本质不是单调性, 单调性的题目一定可以二分, 可以二分的题目不一定有单调性
二分的本质是边界
二分法用于查找, 每次都选择答案所在的区间再次进行查找, 当区间长度为 1时, 就是答案
二分算法模板
int bsearch_l(int l, int r) {
while (l < r) {
int mid = (l + r) / 2;
if (check[mid]) // check 判断mid是否满足条件
r = mid;
else
l = mid + 1;
}
return l;
}
int bsearch_r(int l, int r) {
while (l < r) {
int mid = (l + r + 1 ) / 2;
if (check[mid]) // check 判断mid是否满足条件
r = mid;
else
l = mid -1 ;
}
return l;
}
答案代码
import java.util.*;
public class Main{
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner reader = new Scanner(System.in);
int a = reader.nextInt();
int b = reader.nextInt();
int arr[] = new int[a];
for (int i = 0; i < a; i++)
arr[i] = reader.nextInt();
while (b-- != 0) {
int x = reader.nextInt();
int l = 0;
int r = a - 1;
// 找左边边界
while (l < r) {
int mid = l + r >> 1;
if (arr[mid] >= x) {
r = mid;
} else {
l = mid + 1;
}
}
//若找出的值不是与之前匹配的值,说明没找到,直接输出没找到的结果即可。
if (arr[l] != x) {
System.out.println("-1 -1");
} else {
System.out.print(l + " ");
l = 0;
r = a - 1;
//找出右边界
while (l < r) {
int mid = l + r + 1 >> 2;
if (arr[mid] <= x)
l = mid;
else
r = mid - 1;
}
System.out.println(l);
}
}
}
}