一、题目描述
题目来源:ACwing789
给定一个按照升序排列的长度为 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
二、思路
这题我最先尝试的是使用暴力解,最后提交代码显示只通过了10/14的数据样本。并且会显示Time Limited Exceed的错误。
后面学习了二分算法,使用二分算法进行优化后提交后状态变为Accepted。使用二分查找的思路是先找到数组中是否存在这个元素,不存在按题意返回,若存在,则查找到的是该元素的第一次出现的位置,后面再使用一次二分查找,找到该元素最后一次出现的位置。注意两次二分查找的mid值不同,以及l,r变换的条件不同。
三、C++代码
版本一:暴力解代码
#include<bits/stdc++.h>
using namespace std;
//数的范围
#define maxsize 100010
int a[maxsize];
int b[maxsize];
int main(){
int n,q;
cin>>n>>q;
int k;
int number;
for(int i=0;i<n;i++){
cin>>a[i];
}
for(int i=0;i<q;i++){
cin>>b[i];
}
for(int i=0;i<q;i++){
k=0;
number=0;
for(int j=0;j<n;j++){
if((a[j]==b[i])&&(k==0)&&(j!=0)){
if(number==0){
k=j;
}
number++;
}
if((a[j]==b[i])&&(j==0)){
number++;
}
if((a[j]==b[i])&&(k!=0)){
number++;
}
}
if((k!=0)&&(number!=0)){
cout<<k<<" "<<k+number-2;
}else if((k==0)&&(number!=0)){
cout<<k<<" "<<k+number-1;
}else{
cout<<"-1"<<" "<<"-1";
}
cout<<"\n";
}
}
版本二:二分查找优化版
#include<bits/stdc++.h>
using namespace std;
//数的范围-二分查找版
#define maxsize 100010
int a[maxsize];
int main(){
int n,q;
cin>>n>>q;
for(int i=0;i<n;i++){
cin>>a[i];
}
while(q--){
int k;
cin>>k;
int l=0,r=n-1;
while(l<r){
int mid=(l+r)/2;
if(a[mid]<k){
l=mid+1;
}else{
r=mid;
}
}
if(a[r]==k){
cout<<r<<" ";
r=n-1;
while(l<r){
int mid=(l+r+1)/2;
if(a[mid]>k){
r=mid-1;
}else{
l=mid;
}
}
cout<<l<<endl;
}else{
cout<<"-1"<<" "<<"-1"<<endl;
}
}
return 0;
}