题目
给定一个按照升序排列的长度为 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
分析
对于输入 数组1 2 2 3 3 4,如果k=3,则输出为 “3(第一次出现的下标) 4(最后出现的下标) ”
数组有序,使用二分的思想可较好的解决,怎么二分呢?每一次二分的结果都只能有一个结果,所以分两次二分,一次找到最左边的3,一次找到最右边的3;
对于最左边的3,利用二分的思想,他就是想到找到的值,如果arr[mid]的值大于等于3,则right = mid(用等于是因为arr[mid]可能是目标值),否则left = mid+1(arr[mid]不可能是目标值,向右移移一位);
对于最右边的3,利用二分的思想,他就是想到找到的值,如果arr[mid]的值小于等于3,则left = mid(用等于是因为arr[mid]可能是目标值),否则right= mid-1(arr[mid]不可能是目标值,向左移一位);
代码
import java.util.*;
public class Main{
public static void main(String arg[]){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int q = sc.nextInt();
int[] temp = new int[n];
for(int i = 0;i<n;i++){
temp[i] = sc.nextInt();
}
for(int j = 0;j<q;j++){
int k = sc.nextInt();
int l = 0;
int r = n-1;
while(l<r){
int mid = l+r >>1;
if(temp[mid] >= k){//左边界
r = mid;
}else{
l = mid +1;
}
}
if(temp[l] != k){//没有目标值,此时temp[l]为大于k的第一个值
System.out.println("-1 -1");
continue;
}else{
System.out.print(l+" ");
}
l = 0;
r = n-1;
while(l<r){
int mid = l+r+1>>1; //+1处理边界 有减一需加一
if(temp[mid] <= k){//右边界
l = mid;
}else{
r = mid -1;
}
}
System.out.println(l);
}
}
}