Google面试题 数组中第K小的数字

来源:互联网 发布:五十知天命六大而耳顺 编辑:程序博客网 时间:2024/05/21 07:52
题目描述:

    给定两个整型数组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;elseL=mid;}printf("%lld\n",L);}return 0;}



1 0
原创粉丝点击