您的位置:首页 > 其它

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

2013-11-28 10:30 99 查看
问题:有两个单调递增的数组 a
和 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;
		else
			least = 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 函数中可以看出算法的思想很简单。但是我本人对这个算法不是很满意,希望能找到更好的算法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐