题目描述:
给定两个整型数组A和B。我们将A和B中的元素两两相加可以得到数组C。
譬如A为[1,2],B为[3,4].那么由A和B中的元素两两相加得到的数组C为[4,5,5,6]。
现在给你数组A和B,求由A和B两两相加得到的数组C中,第K小的数字。
输入:
输入可能包含多个测试案例。
对于每个测试案例,输入的第一行为三个整数m,n, k(1<=m,n<=100000, 1<= k <= n *m):n,m代表将要输入数组A和B的长度。
紧接着两行, 分别有m和n个数, 代表数组A和B中的元素。数组元素范围为[0,1e9]。
输出:
对应每个测试案例,
输出由A和B中元素两两相加得到的数组c中第K小的数字。
样例输入:
2 2 3
1 2
3 4
3 3 4
1 2 7
3 4 5
样例输出:
5
给定两个整型数组A和B。我们将A和B中的元素两两相加可以得到数组C。
譬如A为[1,2],B为[3,4].那么由A和B中的元素两两相加得到的数组C为[4,5,5,6]。
现在给你数组A和B,求由A和B两两相加得到的数组C中,第K小的数字。
输入:
输入可能包含多个测试案例。
对于每个测试案例,输入的第一行为三个整数m,n, k(1<=m,n<=100000, 1<= k <= n *m):n,m代表将要输入数组A和B的长度。
紧接着两行, 分别有m和n个数, 代表数组A和B中的元素。数组元素范围为[0,1e9]。
输出:
对应每个测试案例,
输出由A和B中元素两两相加得到的数组c中第K小的数字。
样例输入:
2 2 3
1 2
3 4
3 3 4
1 2 7
3 4 5
样例输出:
5
6
算法分析:题目看上去貌似很简单,但如果直接排序则会超时。一般二分查找用于在顺序的序列中查找,这里用到的是二分逼近。
C语言版本
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
long long m,n,k;
int CompareLongLong(const void *a,const void *b)
{
return*(long long *)a-*(long long *)b;
}
//返回小于mid的个数
long long LessThanMid(long long mid,long long *pm,long long *pn)
{
long long count=0;
long long i,j=n-1;
//i从前向后扫
for(i=0; i<m; i++)
{
//j从后向前扫,达到临界,j前所有数+*(pm+i)均大于mid,一趟下来获得j+1个
while(j>=0&&(*(pm+i)+*(pn+j))>mid)j--;
count=count+j+1;
}
return count;
}
int main()
{
long long *pm,*pn,i,low,high,mid,ans,count;
pm=pn=NULL;
while(~scanf("%lld %lld %lld",&m,&n,&k))
{
pm=(long long *)malloc(sizeof(long long)*m);
pn=(long long *)malloc(sizeof(long long)*n);
for(i=0; i<m; i++)
{
scanf("%lld",pm+i);
}
for(i=0; i<n; i++)
{
scanf("%lld",pn+i);
}
//两个数组变为顺序
qsort(pm,m,sizeof(long long),CompareLongLong);
qsort(pn,n,sizeof(long long),CompareLongLong);
//最小值
low=*pm+*pn;
//最大值
high=*(pm+m-1)+*(pn+n-1);
//二分逼近
while(low<=high)
{
mid=(low+high)/2;
count=LessThanMid(mid,pm,pn);
//大于mid的个数在k的右面
if(count>=k)
{
ans=mid;//打擂,将更接近的mid给ans
high=mid-1;
}
else
{
low=mid+1;
}
}
printf("%lld\n",ans);
free(pm);
free(pn);
}
return 0;
}
C++版本
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<math.h>
#include<algorithm>
using namespace std;
int a[100001],b[100001];
long long m,n,k;
int RightOfK(long long mid,long long k)
{
long long i,j,count=0;
j=n-1;
for(i=0;i<m;i++)
{
while(a[i]+b[j]>mid&&j>=0)j--;
if(j<0) break;
count=count+j+1;
if(count>=k) return 1;//小于mid总共有count个,现在在k的右面
}
return 0;
}
int main()
{
int i;
long long R,L,mid;
while(scanf("%lld%lld%lld",&m,&n,&k)!=EOF)
{
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(i=0;i<m;i++)scanf("%d",&a[i]);
for(i=0;i<n;i++)scanf("%d",&b[i]);
sort(a,a+m);
sort(b,b+n);
L=a[0]+b[0];//最小值
R=a[m-1]+b[n-1];//最大值
while(L<R)
{
mid=(L+R+1)/2;
if(RightOfK(mid-1,k)) R=mid-1;
else L=mid;
}
printf("%lld\n",L);
}
return 0;
}