面试题精选(78):输出两有序数组和的前k项(O(klgk)复杂度)

题目描述:

Let A and B are sorted array with length m and n respectively, given k, the problem is to find the first k smallest elements which are composed of A[i]+B[j].
e.g.
A={1,3,5,7}, B={2,6, 10}, k = 3
 
Output:
1+2
3+2
1+6

 

分析:

不晓得有没有时间复杂度更小的算法,目前只想到用堆来实现,时间复杂度为O(klgk)

 

use a min-heap of pairs (ik,jk), using ordering on A[ik] + B[jk]
Initialize the heap with pairs (ik=k, jk=0) for k=0..n-1
On removing (ix,jx), replace it with (ix,jx+1)

代码实现:

 

template <typename T>
class Sum
{
    T a;
    T b;
public:
    Sum(T a,T b)
    {
        this->a=a;
        this->b=b;
    };
    T getSum() const
    {
        return a+b;
    };
    void print()
    {
        cout<<endl<<"("<<a<<"+"<<b<<")"<<endl;
    };

    /////自定义数据想用functional函数less<>,greater<>,必须重载< 或 >操作符
    friend bool operator > (const Sum<T>& s1,const Sum<T>& s2);
};

/////
bool operator > (const Sum<int>& s1,const Sum<int>& s2)
{
    return s1.getSum()>s2.getSum();
}


int main()
{

    vector<Sum<int> > vSum;
    int A[]={1,2,3};
    int B[]={2,3,4,5};
    int k=7;
    int count=0;
    int m,n;
    int sizeA=sizeof(A)/sizeof(int);
    int sizeB=sizeof(B)/sizeof(int);
    for(m=0;m<sizeA;m++)
    {
        for(n=0;n<sizeB;n++)
        {
            if(count!=k)
            {
               vSum.push_back(Sum<int>(A[m],B[n]));
               count++;
            }
            else
                break;
        }
        if(count==k)
            break;
    }
   
    make_heap(vSum.begin(),vSum.end(),greater<Sum<int> >());
   
    count=0;
    m=k/sizeA-1;
    n=k%sizeB;
    for(;m<sizeA;m++)
    {
        for(;n<sizeB;n++)
        {
            pop_heap(vSum.begin(),vSum.end(),greater<Sum<int> >());
            /////pop非真正pop,放在容器末尾
            vSum.back().print();
            vSum.pop_back();

            count++;
            if(count==k)
            {
                break;
            }
            vSum.push_back(Sum<int>(A[m],B[n]));
            push_heap(vSum.begin(),vSum.end(),greater<Sum<int> >());

        }
        if(count==k)
            break;
        if(n==4)
            n=0;
    }

    ////所用的Sum对象push_heap之后,还未输出足够需要的Sum,则继续pop_heap
    while(count<k)
    {
        pop_heap(vSum.begin(),vSum.end(),greater<Sum<int> >());
        vSum.back().print();
        vSum.pop_back();
        count++;
    }

    system("pause");
    return 0;
}

运行结果:

面试题精选(78):输出两有序数组和的前k项(O(klgk)复杂度)_第1张图片

 

你可能感兴趣的:(算法,面试,less,System,output)