给定大量间隔[ai,bi], 找到与最多间隔相交的间隔。 我们可以在O(nlogn)或更好的地方做到这一点吗?我只能想到一个n ^ 2方法。
答案 0 :(得分:13)
假设间隔为(a1,b1), ..., (an,bn)
。制作一个长度为2n
的排序数组,其中的关系被
ai = aj
,则先将ai
置于if bi < bj
bi = bj
,则先将bi
置于if ai < aj
ai = bj
,然后将ai
放在首位将每个点标记为a
或b
(可能保留长度为2n
的二进制数组来执行此操作)。遍历数组,跟踪触摸给定点的间隔数(运行总计a
s减去总计b
s)。遇到的最大数量发生在重叠最多的时间间隔。
由于间隔的排序,这是O(n log n)
。
答案 1 :(得分:4)
使用间隔树: http://en.wikipedia.org/wiki/Interval_tree。
如果使用居中间隔树,复杂度为O(nlogn + m),其中m是交叉点的总数(最差情况m = n ^ 2)。
答案 2 :(得分:2)
根据PengOne的回答,我做了一个简单的实现,使用两个n排列数组而不是2n数组。
1) Construct two n arrays, one is sort by ai, another is sort by bi.
make sure that if ai==aj, then bi<bj, but i before j, the same as b-array.
2) Walk through the b-array for each b, Do a binary search in a-array to find
index, make sure a[index]<=b<a[index+1]
3) find the max(index - i + 1), the the bi is the point we need.
代码
public int getPoint(List<Interval> intervals) {
// validation
if (intervals == null || intervals.size() == 0) {
return 0;
}
List<Interval> sortA = sortByA(intervals);
List<Interval> sortB = sortByB(intervals);
int max = 0;
int maxPoint = sortB.get(0).b;
for (int i = 0; i < sortB.size(); i++) {
Interval interval = sortB.get(i);
// find B in sortA.
int index = search(sortA, interval.b);
int count = index - i + 1;
if (count > max) {
max = count;
maxPoint = sortB.get(i).b;
}
}
return maxPoint;
}
答案 3 :(得分:1)
如果值ai和bi不是小整数&lt; N然后可以通过对所有不同ai和bi值列表中的索引进行排序来减少它们。
给定输入“list”,其中包含所有不同的ai和bi。排序后的索引位于C#:
int [] index = Enumerable.Range(0,list.Count).OrderBy(i =&gt; list [i])。ToArray();
通过反转该排列,可以为每个ai和bi分配从0到N-1的值。
int [] values = invertPermutation(index);
ai可以替换为值[location_of_ai_in_List]
现在可以制作新的ai和bi&lt; N有一个巧妙的技巧来找到O(N)中的最大重叠间隔,以及其他一些查询可以快速响应。
声明一个N + 1个元素的数组:
int [] sum = new int [N + 1];
每个间隔执行:
和[Al] ++;
和[双+ 1] - ;
//由于我们处理O(1)中的每个区间,因此该步骤的总复杂度为O(N)。
骨料:
for(int i = 1; i&lt; = N; i ++) { sum [i] + = sum [i - 1]; }
//这是一个O(N)步骤。
这个区间[ai,bi]是一个解,它与所有其他区间相交的次数是“sum [k] - 1”(不考虑自身)。
答案 4 :(得分:0)
如果ai,bi是小整数(例如,它们可能是16位数),则可能适用于间隔树的替代方法是:
迭代j处的x值给出了与点j相交的间隔数,因此找到最大值会得到与最大间隔相交的点。
这需要O(N + n)个周期,所以只有在你的应用中n> N时才有用。
(严格来说,这并没有回答这个问题,因为它找到了相交最多的点。但是,你应该能够扩展这种方法来找到最相交的区间。)
答案 5 :(得分:-1)
你可以在n。
中完成[最小的ai,最大的bi]
所以..
varmin = interval[0]['begin']
varmax = interval[0]['end']
foreach( interval as rang ) {
varmin = min( rang['begin'], varmin )
varmax = max( rang['end'], varmax ) }
newrange = array('begin'=>varmin,'end'=>varmax)