【发布时间】:2012-03-12 18:09:37
【问题描述】:
给定很多区间 [ai, bi], 找到与最多间隔数相交的间隔。 我们可以在 O(nlogn) 或更好的时间内做到这一点吗?我只能想到一个 n^2 的方法。
【问题讨论】:
给定很多区间 [ai, bi], 找到与最多间隔数相交的间隔。 我们可以在 O(nlogn) 或更好的时间内做到这一点吗?我只能想到一个 n^2 的方法。
【问题讨论】:
假设间隔为(a1,b1), ..., (an,bn)。制作一个长度为 2n 的排序数组,其中关系被打破
ai = aj,那么把ai放在前面,如果bi < bj
bi = bj,那么把bi放在前面,如果ai < aj
ai = bj,则将ai放在首位将每个点标记为a 或b(可能保留一个长度为2n 的二进制数组来执行此操作)。遍历数组,跟踪有多少间隔接触给定点(运行总数 as 减去运行总数 bs)。遇到的最大数量发生在重叠最多的区间。
这是O(n log n),由于间隔的排序。
【讨论】:
(a1,b1),(a2,b2),(a3,b3) = (1,2),(1,3),(2,4),则排序顺序为a2,a1,b1,a3,b2,b3。
使用区间树: http://en.wikipedia.org/wiki/Interval_tree.
如果使用居中区间树,复杂度为 O(nlogn + m),其中 m 是交叉点的总数(最坏情况 m=n^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;
}
【讨论】:
如果 ai 和 bi 不是小于 N 的小整数,那么可以通过对所有不同 ai 和 bi 值的列表中的索引进行排序来减少它们。
给定输入“列表”,其中包含所有不同的 ai 和 bi。排序索引在 C# 中:
int[] index = Enumerable.Range(0, list.Count).OrderBy(i => list[i]).ToArray();
通过反转该排列,可以为每个 ai 和 bi 分配一个从 0 到 N - 1 的值。
int[] values = invertPermutation(index);
ai 可以替换为值[location_of_ai_in_List]
现在考虑到新的 ai 和 bi 可以
声明一个包含 N+1 个元素的数组:
int[] sum = new int[N+1];
对于每个间隔执行:
sum[ai]++;
sum[bi+1]--;
//这一步的总复杂度是O(N),因为我们在O(1)中处理每个区间。
聚合:
for (int i = 1; i
//这是一个O(N)步。
这个区间 [ai, bi] 是一个解,它与所有其他区间相交的次数是“sum[k] - 1”(不考虑自身)。
【讨论】:
如果 ai,bi 是小整数(例如,它们可能是 16 位数字),可能适用的区间树替代方法是:
在迭代 j 处 x 的值给出了与点 j 相交的区间数,因此找到最大值给出与最多区间相交的点。
这需要 O(N+n) 个周期,因此仅当 n>N 对您的应用程序有用。
(严格来说,这并不能回答问题,因为它会找到最相交的点。但是,您应该能够扩展这种方法以找到最相交的区间。)
【讨论】:
你可以在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)
【讨论】: