给出大量间隔[ai,bi],找到与最多间隔相交的间隔

时间:2012-03-12 18:09:37

标签: algorithm data-structures

给定大量间隔[ai,bi], 找到与最多间隔相交的间隔。 我们可以在O(nlogn)或更好的地方做到这一点吗?我只能想到一个n ^ 2方法。

6 个答案:

答案 0 :(得分:13)

假设间隔为(a1,b1), ..., (an,bn)。制作一个长度为2n的排序数组,其中的关系被

打破
  • 如果ai = aj,则先将ai置于if bi < bj
  • 如果bi = bj,则先将bi置于if ai < aj
  • if ai = bj,然后将ai放在首位

将每个点标记为ab(可能保留长度为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)中的最大重叠间隔,以及其他一些查询可以快速响应。

  1. 声明一个N + 1个元素的数组:

    int [] sum = new int [N + 1];

  2. 每个间隔执行:

    和[Al] ++;

    和[双+ 1] - ;

  3. //由于我们处理O(1)中的每个区间,因此该步骤的总复杂度为O(N)。

    1. 骨料:

      for(int i = 1; i&lt; = N; i ++) {     sum [i] + = sum [i - 1]; }

    2. //这是一个O(N)步骤。

      1. 找到sum [k]最大的位置k。
      2. 迭代新的区间[ai,bi]并找到包含位置k的第一个区间(即ai&lt; = k&amp;&amp; k&lt; = bi)。
      3. 这个区间[ai,bi]是一个解,它与所有其他区间相交的次数是“sum [k] - 1”(不考虑自身)。

答案 4 :(得分:0)

如果ai,bi是小整数(例如,它们可能是16位数),则可能适用于间隔树的替代方法是:

  1. 制作一个N值的数组A,其中N大于max(bi)
  2. 将数组中的所有值清除为0
  3. 循环间隔并更改A [ai]:= A [ai] +1,A [bi + 1]:= A [bi + 1] -1
  4. 设置x = 0
  5. 遍历数组计算x:= x + A [j],并查找x的最大值
  6. 迭代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)