考虑下面描述连续范围的 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:让我规定一些事情,整数值的绝对最小值和最大值将从(0, 20000)开始。其次,IRange的平均数量将在100左右。我不知道这是否会改变算法的设计方式。
编辑3:我正在一个科学仪器(质谱仪)上实现这个算法,在这个仪器上,数据处理的速度对数据的质量至关重要(更快的分析时间=在时间T内收集更多的光谱)。固件语言(专有)只有数组[],而且不是面向对象的。我选择C#,因为我擅长在这两种语言之间移植概念,并认为在SO社区的利益上,一个好的答案会有更广泛的受众。
for(var i = 0; i < array.length; i++) for(var j = i + 1; j < array.Length; j++) max = Math.max(max, GetOverlap(array[i], array[j]));
- Alxandr