求两个升序序列的和中最小的k个数

这篇博客探讨了如何高效地解决一个数学问题:给定两个升序排列的序列A和B,找出它们对应元素相加后的k个最小和。通过分析有序序列的性质,提出利用有序性避免排序,直接找到i与j的取值来得到最小k个数之和,从而提高算法效率。

题目

有两个序列A和B,A=(a1,a2,…,ak),B=(b1,b2,…,bk),A和B都按升序排列。对于1<=i,j<=k,求k个最小的(ai+bj)。要求算法尽量高效。

分析

我们可以使用快速排序或堆排序将相加后的数组进行排序,然后取出最小的k个数即可,但是这样的话,题目中有一个条件没有用到,那就是序列A和序列B都是有序的。如果用上这个条件是不是有更高效的方法呢?

由于序列A和B都是按升序排列,那么假设ai + bj <= C, 那么任意的0 <= p < i and 0 <= q < j,都会有ap + bq <= ai + bj, 因此我们若想找到k个最小的(ai+bj),只需要找到使得(i-1) * j < k或者(j-1) * i < k,当然获得的是其中最小的一个值的情况下的i与j的取值,获取到i与j的值过后,那么p与q的取值相加就是最小的k个和。

代码如下:

#include<iostream>
using namespace std;

int A[] = {3, 9, 12, 20, 23, 34, 39};
int B[] = {1, 10, 15, 19, 25, 39, 47};
int k = sizeof(A)/sizeof(A[0]);
int p, q; 

int *KMinSelect(int *a, int *b, int k){
    int i = k, j = k;
    int count = 0;
    int *temp = new int[k];
    while(i>0 && j>0){
        if(a[i-1] > b[j-1]){
            if((i-1)*j >= k){
                i--;
            } else {
                break;
            }
        } else {
            if((j-1)*i >= k){
                j--;
            } else{
                break;
            }
        }
    }
    if(a[i-1] > b[j-1]){
        for(int p=0; p<i; p++)
            for(int q=0; q<j; q++)
                if(count < k)
                    temp[count++] = a[p] + b[q];
    } else {
        for(int q=0; q<j; q++)
            for(int p=0; p<i; p++)
                if(count < k)
                    temp[count++] = a[p] + b[q];
    }
    return temp;
}

int main(){
    int *result = KMinSelect(A, B, k);
    for(int i=0; i<k; i++)
        cout << *(result+i) << " ";
    cout << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值