最大间隙问题


问题描述:已知一个整数数组a[],其长度为n,要找出数组中相邻元素的最大间距。

分析:问题很简单,而且描述本身就暗示了一种自然的求解方法,即先对元素排序,然后逐个求相邻元素的间距。这种解法的复杂度为O(n*logn)。再想一下,设min, max分别是数组中的最小和最大元素,len = (max-min)/n-1那么最大间距maxGap >= len。把a分成长度为len的区间,即[min, min+len), [min+len, min+2*len), ..., [max-len, max],最大间距一定是落在相邻的两个区间,或者不相邻但中间区间没有元素的两个区间,并且是在前一个区间的最大值和后一个区间的最小值之间产生。所以只需找出每一个区间的最大值和最小值,然后扫描一遍就能求出最大间距。

#define MAXINT (1<<31)-1
#define MININT 1<<31
typedef struct _bucket { int min, max; } Bucket; int maxGap(int *a, int n) { int max = MININT, min = MAXINT, i; double bucketLen; for(i = 0; i < n; ++i) { if(a[i] > max) max = a[i]; if(a[i] < min) min = a[i]; } bucketLen = (max-min) * 1.0 / (n-1); Bucket *bucket = new Bucket[n-1]; for(i = 0; i < n-1; ++i) { bucket[i].max = MININT; bucket[i].min = MAXINT; } bucket[0].max = min; bucket[0].min = min; bucket[n-2].max = max; bucket[n-2].min = max; for(i = 0; i < n; ++i) { int index; if(a[i] != min && a[i] != max) { index = (a[i]-min) * 1.0 / bucketLen; if(bucket[index].max < a[i]) bucket[index].max = a[i]; if(bucket[index].min > a[i]) bucket[index].min = a[i]; } } int low = -1, high = -1, maxGap = 0, curGap, pre = 0; for(i = 1; i < n-1; ++i) { if(bucket[i].max != MININT) { curGap = bucket[i].min - bucket[pre].max; if(curGap > maxGap) { maxGap = curGap; low = bucket[pre].max, high = bucket[i].min; } pre = i; } } printf("the maximum gap is %d, between %d and %d!\n", maxGap, low, high); return maxGap; } int main() { int a[] = {1,8,4,5,6}; maxGap(a,5); return 0; }

这种将元素分段(也可以叫做分桶)的思想也可用于求解找出位于多个不同机器上的第k大元素的问题,这类问题的描述如下:

有n个不同位置的主机,每个主机上有很多的整数,要求找出所有主机上的第k大到第k+m大的元素。算法应该使主机之间的通信量尽可能地小。

算法思想:

1. 选一个适当的桶大小len, 统计每个主机落在每个桶中的元素数目

2. 将1得到的统计信息汇总起来,确定第k大到第k+m大的元素位于哪些桶中

3. 将各个主机上这些桶中的元素集中到一起,再用排序或者最小堆找出第k大元素到第k+m大元素

这种方法关键在于桶大小的选取,太大的话上面算法第3步传输的数据会比较多,太小第2步传输的统计信息又会比较多。理想状态下第k大到第k+m大的元素位于一个桶中,这样只需要传输一个桶大小的数据。所以,可以把桶大小选为和m一个量级。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM