算法题:两数组所有和值的最小前 k 项

来源:互联网 发布:安卓mac地址修改器 编辑:程序博客网 时间:2024/05/16 14:43

问题:有两个单调递增的数组 a[n] 和 b[m],这两个数组的和值 a[i]+b[j],其中 i=1, ..., n,j=1, ..., m,共有 n*m 个,要求返回前 k 项最小的和。例如:a[4] = {-5, 2, 7, 14},b[4]={-3, -1, 15, 21} 时,要求返回前 8 个时为:-8, -6, -1, 1, 4, 6, 10, 11。

数组和值表

 

具体的程序如下:

#include <stdio.h>#include <stdlib.h>#define max(a,b) ((a)>=(b) ? (a) : (b))int a[4] = {-5, 2, 7, 14};int b[4] = {-3, -1, 15, 21};int n  = sizeof(a)/sizeof(a[0]); //数组a的长度int m = sizeof(b)/sizeof(b[0]); //数组b的长度struct point {int x;int y;};int ptcmp(struct point pt1, struct point pt2){return a[pt1.x]+b[pt1.y]-a[pt2.x]-b[pt2.y];}void minheapify(struct point *arr, int i,  int len){int least, l, r;struct point temppt;l = 2*i + 1;r = 2*i + 2;if (len>1) {if (l < len && ptcmp(arr[l], arr[i]) < 0)least = l;elseleast = i;if (r < len && ptcmp(arr[r], arr[least]) < 0)least = r;if (least != i) {temppt = arr[i];arr[i] = arr[least];arr[least] = temppt;minheapify(arr, least, len);}}}struct point heapexactmin(struct point *arr,int *lenpt){struct point temppt;if (*lenpt < 1) {printf("heap underflow\n");exit(1);}//交换数组的第一个元素和最后一个元素temppt = arr[0];arr[0] = arr[*lenpt-1];arr[*lenpt-1] = temppt;*lenpt = *lenpt - 1;//保持最小堆minheapify(arr, 0, *lenpt);return arr[*lenpt];}void heapinsert(struct point *arr, int *lenpt, struct point newpt){int i;struct point temppt;arr[*lenpt] = newpt;*lenpt = *lenpt + 1;i = *lenpt - 1;while ((i-1)/2 >= 0 && ptcmp(arr[i], arr[(i-1)/2]) < 0) {temppt = arr[i];arr[i] = arr[(i-1)/2];arr[(i-1)/2] = temppt;i = (i-1)/2;}}int main(){int candnum;struct point *cand;struct point minpt, rpt, dpt;int i, count, k;int *kminsum;printf("Please enter a positive integer number no more than %d for variable k:\n", m*n);scanf("%d", &k);kminsum = (int *) malloc(k*sizeof(int));cand = (struct point *) malloc(max(n,m)*sizeof(struct point));//初始化 cand 数组cand[0].x = 0;cand[0].y = 0;candnum = 1;count = 0;while (count < k) {minpt = heapexactmin(cand, &candnum);kminsum[count] = a[minpt.x] + b[minpt.y];//判断 minpt 右边的点能否加进 cand 数组rpt.x = minpt.x;rpt.y = minpt.y+1;if (rpt.y < m) {for (i=0; i<candnum && (rpt.x != cand[i].x || rpt.y != cand[i].y); i++);if (i >= candnum)heapinsert(cand, &candnum, rpt);}//判断 minpt 下边的点能否加进 cand 数组dpt.x = minpt.x+1;dpt.y = minpt.y;if (dpt.x < n) {for (i=0; i<candnum && (dpt.x != cand[i].x || dpt.y != cand[i].y); i++);if (i >= candnum)heapinsert(cand, &candnum, dpt);}count++;}for (count = 0; count < k; count++)printf("%d ", kminsum[count]);printf("%\n");return 0;}

注:在这里我用到了堆的相关操作,其实是不必要的。只不过是我想练习一下堆的相关操作而已。从 main 函数中可以看出算法的思想很简单。但是我本人对这个算法不是很满意,希望能找到更好的算法。

原创粉丝点击