算法题:两数组所有和值的最小前 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。
具体的程序如下:
注:在这里我用到了堆的相关操作,其实是不必要的。只不过是我想练习一下堆的相关操作而已。从 main 函数中可以看出算法的思想很简单。但是我本人对这个算法不是很满意,希望能找到更好的算法。
和 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 函数中可以看出算法的思想很简单。但是我本人对这个算法不是很满意,希望能找到更好的算法。
相关文章推荐
- Java编程:定义一个int型的一维数组,包含10个元素,分别赋一些随机整数,然后求出所有元素的最大值,最小值,平均值,和值,并输出出来。
- 面试常考算法题 局部最小 求二叉树结点 求两个数组中所有数的上中位数 两个数组的所有数中第K小的数
- 输入一个整数数组,返回所有元素两两之差绝对值最小的值,O(n)算法
- 定义一个int型的一维数组,包含10个元素,分别赋一些随机整数,然后求出所有元素的最大值,最小值,平均值,和值,并输出出来。
- 定义一个int型的一维数组,包含10个元素,分别赋一些随机整数,然后求出所有元素的最大值,最小值,平均值,和值,并输出出来。
- 从数组中查找出最大最小两数的log(n)算法
- 每日一道算法题:打印一维数组的所有组合
- Comparator 实现集合中元素的比较.输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这321323
- 给定一个有序整数数组,元素各不相同且按照升序排列,编写一个算法,创建一个高度最小的二叉查找树
- 从长度为N的数组中找出所有M个元素组合的优化算法
- 随机产生20个[10 , 50]的正整数存到数组中,并求数组中的所有元素最大值、最小值、平均值以及各元素之和,及第二大值。
- 算法题:求从n个数组任意选取一个元素的所有组合
- 把数组排成最小的数[算法]
- ios 数组最大值,最小值,平均值,和的快速算法
- 算法题目---旋转数组的最小数字
- 设计一个最优算法来查找n个元素数组中的最大值和最小值
- 算法题: 求一个整数数组中,通过元素加减运算得到指定结果的所有运算过程. 例如【5,4,6,7,1】= 9 ?
- 对“求数组中所有和为某固定数的所有数对”的算法的简单思考
- 算法复习:旋转数组的最小数字
- 求一个数组中的最大值和最小值的算法改进 php 实现