考虑以下界面,该界面描述了integer
值的连续范围。
public interface IRange {
int Minimum { get;}
int Maximum { get;}
IRange LargestOverlapRange(IEnumerable<IRange> ranges);
}
我正在寻找一种有效的算法来查找给定IRange
个对象列表的最大重叠范围。下图简要概述了这个想法。顶部数字表示integer
值,|-----|
表示具有最小值和最大值的IRange
个对象。我堆叠了IRange
个对象,以便解决方案很容易可视化。
0123456789 ... N
|-------| |------------| |-----|
|---------| |---|
|---| |------------|
|--------| |---------------|
|----------|
此处,LargestOverlapRange
方法将返回:
|---|
由于该范围总共有4个'重叠'。如果有两个单独的IRange
具有相同数量的重叠,我想返回null
。
以下是我尝试过的一些简要代码。
public class Range : IRange
{
public IRange LargestOverlapRange(IEnumerable<IRange> ranges) {
int maxInt = 20000;
// Create a histogram of the counts
int[] histogram = new int[maxInt];
foreach(IRange range in ranges) {
for(int i=range.Minimum; i <= range.Maximum; i++) {
histogram[i]++;
}
}
// Find the mode of the histogram
int mode = 0;
int bin = 0;
for(int i =0; i < maxInt; i++) {
if(histogram[i] > mode) {
mode = histogram[i];
bin = i;
}
}
// Construct a new range of the mode values, if they are continuous
Range range;
for(int i = bin; i < maxInt; i++) {
if(histogram[i] == mode) {
if(range != null)
return null; // violates two ranges with the same mode
range = new Range();
range.Minimum = i;
while(i < maxInt && histrogram[i] == mode)
i++;
range.Maximum = i;
}
}
return range;
}
}
这涉及四个循环,如果不是更高则很容易为O(n ^ 2)。是否有更有效的算法(速度方式)从其他范围列表中找到最大的重叠范围?
修改
是的,O(n ^ 2)不正确,我正在考虑错误。它应该是O(N * M),正如评论中所指出的那样。
编辑2
让我说明一些事情,integer
值的绝对最小值和最大值将来自(0,20000)。其次,IRange
的平均数量将在100的数量级。我不知道这是否会改变算法的设计方式。
编辑3
我在科学仪器(质谱仪)上实施该算法,其中数据处理的速度对于数据质量是最重要的(更快的分析时间=在时间T中收集的更多光谱)。固件语言(专有)仅具有数组[],并且不是面向对象的。我之所以选择C#是因为我在两种语言之间移植概念方面很不错,并认为为了SO社区的利益,一个好的答案会有更广泛的受众。
答案 0 :(得分:10)
将范围列表转换为起点和终点列表。使用O(n log n)算法对列表进行排序。现在,您可以遍历列表并递增或递减计数器,具体取决于它是开始点还是停止点,这将为您提供当前的重叠深度。
答案 1 :(得分:1)
正如我理解OP的问题,给出3个范围的解决方案
A: 012
B: 123
C: 34
将是范围12
(A和B的常见子集), 不 范围123
(因为它不是任何一对的共同子集。)
在编写任何代码之前考虑一下纸上的算法。动态编程解决方案怎么样? (如果您不了解动态编程,那么值得在书中阅读)。动态编程的想法是建立更简单的子问题的解决方案。
设f_i(n, k)
为从n个共同开始的最长间隔的大小,至少是给定范围的至少k个。
您可以从f_0开始计算f_1,从f_1开始计算f_2,依此类推。更新功能只取决于考虑的额外范围。
假设有M个范围。 f_M的值将告诉我们您的问题的答案。
你所谈到的最深的深度是最大的k,使得某些n的f_M(n,k)不为零。让我们称之为最大深度K.然后我们在n上寻找f_M(n,K)的最大值。它的最大值是你最大范围的大小,从最大化n开始。
最大化n必须是某个范围的下限,所以我们只需要为这些n计算f。有M个范围,所以最多M个下限。因此,该算法具有复杂度O(MMK)。
让第i个范围从a到b
如果n在a到b之外,则没有变化
f_i(n,k) = f_i-1(n,k)
如果n在a到b之间,我们测试通过将新的区间与我们的旧k-1深度解决方案组合而得到的k深度解。如果它比我们已经拥有的更好,我们只使用它。
f_i(n,k) = max ( f_i-1(n,k) , min( f_i-1(n,k-1) , b-n+1))
实施例!适用于0到5,2到6,4到8和6到9的范围。
n 0123456789
...... range 0 to 5
f_1(n,1) 6543210000
..... range 2 to 6
f_2(n,1) 6554321000
f_2(n,2) 0043210000
..... range 4 to 8
f_3(n,1) 6554543210
f_3(n,2) 0043321000
f_3(n,3) 0000210000
.... range 6 to 9
f_4(n,1) 6554544321
f_4(n,2) 0043323210
f_4(n,3) 0000211000
f_4(n,4) 0000000000
因此,最深的深度K是3,最长的范围是4到5.我们还可以看到最长的范围深度2的大小为4,从3开始。