已知两个等长的升序整数序列{a1, a2, ..., ak}和{b1, b2, ..., bk},求序列{ai+bj}的前k小元素,其中1≤i≤k且1≤j≤k,要求时间复杂度尽可能低。
思路:将(1,1,a[1]+b[1])加入一个小根堆
while (堆非空且出堆的元素总数少于k个){
弹出堆顶元素(x, y, a[x]+b[y]);
将(x+1, y, a[x+1]+b[y])和(x, y+1, a[x]+b[y+1])两个点插入堆中;
}
下面的代码使利用了优先队列这种数据结构,实现比较方便。通过定义优先队列,使得每次弹出的元素都是当前元素中最小的一个元素。
#include<stdio.h>
#include<queue>
using namespace std;
class Node{
public:
int a;
int b;
int value;
Node(){
a = 1;
b = 1;
value = 0;
}
Node(int a, int b, int value){
this->a = a;
this->b = b;
this->value = value;
}
friend bool operator<(const Node &a, const Node &b){
return a.value > b.value;
}
};
int main(){
int n, k, i, j;
int orderA, orderB;
int *a, *b;
priority_queue<Node> que;
printf("请输入整数序列的大小:\n");
scanf("%d", &n);
a = (int*)calloc(n+1, sizeof(int));
b = (int*)calloc(n+1, sizeof(int));
printf("请输入递增整数序列a:\n");
for(i=1; i<=n; i++){
scanf("%d", &a[i]);
}
printf("请输入递增整数序列b:\n");
for(i=1; i<=n; i++){
scanf("%d", &b[i]);
}
printf("请输入k值:\n");
scanf("%d", &k);
Node node(1, 1 ,a[1]+b[1]);
que.push(node);
Node cur;
while(k && !que.empty()){
cur = que.top();
que.pop();
orderA = cur.a;
orderB = cur.b;
if(orderA+1<=n && orderB+1<=n){
Node newNode1(orderA+1, orderB, a[orderA+1]+b[orderB]);
Node newNode2(orderA, orderB+1, a[orderA]+b[orderB+1]);
que.push(newNode1);
que.push(newNode2);
}
k--;
}
printf("序列a指针:%d\n序列b的指针:%d\n第k大的值:%d\n",cur.a, cur.b, cur.value);
free(a);
free(b);
return 0;
}