在一个数组中,目标值可能是重复的。二分查找找到目标值后,我们可能需要再进行二分查找,找到另一个相等目标值的位置。
例如题目1,我们的目标是要找到最开始出现的目标值的位置。
例如题目2,我们的目标是要找到最开始出现的目标值的位置和最后一个目标值的位置,最后相减就可以得到目标值共有几个。
题目1:
代码:
#include<stdio.h>
int main(){
int n,m;
scanf("%d %d",&n,&m);
int i;
int a[n],b[m];
for(i=0;i<n;i++){
scanf("%d",&a[i]);
}
for(i=0;i<m;i++){
scanf("%d",&b[i]);
}
for(i=0;i<m;i++){
int left=0;
int right=n-1;
int ans=-2;
while(left<=right){
int mid=(left+right)/2;
if(a[mid]>b[i]){
right=mid-1;
}
else if(a[mid]<b[i]){
left=mid+1;
}
else{
right=mid-1;//一直在缩小范围,所以不会进入死循环
ans=mid;
}
}
printf("%d ",ans+1);
}
return 0;
}
题目2:
思路:
确定A之后,又因为C已知,那我们就在数组中二分查找B(二分查找前提是有序,所以一开始进行快排),又因为B可能重复, 所以记录B有几个,数对就有几个。关键就在于怎么算B有几个,我们可以进行两次二分查找,一次二分查找是找到B最开始出现的位置,另一次二分查找是找到B最后出现的位置,两位置相减加一即为B的个数。
代码:
#include<stdio.h>
int cmp(const void *a,const void *b){
return *(int *)a-*(int *)b;
}
int main(){
int N,C;
scanf("%d %d",&N,&C);
int i;
int a[N];
for(i=0;i<N;i++){
scanf("%d",&a[i]);
}
qsort(a,N,sizeof(a[0]),cmp);
long long ans=0;
for(i=N-1;i>=0;i--){
if(a[i]<=C){
break;
}
int left=0;
int right=i-1;
int res1=-1,res2=-1;
while(left<=right){
int mid=(left+right)/2;
int target=a[i]-C;
if(a[mid]<target){
left=mid+1;
}
else if(a[mid]>target){
right=mid-1;
}
else{
res1=mid;//最大索引:目标值最后出现的位置
left=mid+1;
}
}
// printf("%d ",res1);
left=0;
right=i-1;
while(left<=right){
int mid=(left+right)/2;
int target=a[i]-C;
if(a[mid]<target){
left=mid+1;
}
else if(a[mid]>target){
right=mid-1;
}
else{
res2=mid;//最小索引:目标值最开始出现的位置
right=mid-1;
}
}
// printf("%d\n",res2);
if(res1!=-1){
ans+=res1-res2+1;
}
}
printf("%lld",ans);
}