【问题标题】:giving lots of intervals [ai, bi], find a interval which intersect with the most number of intervals给出很多区间 [ai, bi],找到与最多区间数相交的区间
【发布时间】:2012-03-12 18:09:37
【问题描述】:

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

【问题讨论】:

标签: algorithm data-structures


【解决方案1】:

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

  • 如果ai = aj,那么把ai放在前面,如果bi < bj
  • 如果bi = bj,那么把bi放在前面,如果ai < aj
  • 如果ai = bj,则将ai放在首位

将每个点标记为ab(可能保留一个长度为2n 的二进制数组来执行此操作)。遍历数组,跟踪有多少间隔接触给定点(运行总数 as 减去运行总数 bs)。遇到的最大数量发生在重叠最多的区间。

这是O(n log n),由于间隔的排序。

【讨论】:

  • 你是如何对数组进行排序的,我的意思是基于什么?你能通过对 3 个区间进行排序来告诉我吗,例如取 (1,2)、(1,3)、(2,4)
  • 如果(a1,b1),(a2,b2),(a3,b3) = (1,2),(1,3),(2,4),则排序顺序为a2,a1,b1,a3,b2,b3
  • @PengOne “将每个点标记为 a 或 a b(也许保留一个长度为 2n 的二进制数组来执行此操作)。”我在什么基础上标记一个点?
  • @PengOne 该算法不适用于 (1,3) (2,3.5) (2.5,3) (3.5,4) 也适用于 (1,6) (2,3) (4 ,5) 在这种情况下,答案应该是 1,6 但不是
【解决方案2】:

使用区间树: http://en.wikipedia.org/wiki/Interval_tree.

如果使用居中区间树,复杂度为 O(nlogn + m),其中 m 是交叉点的总数(最坏情况 m=n^2)。

【讨论】:

    【解决方案3】:

    根据 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;
    }
    

    【讨论】:

      【解决方案4】:

      如果 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 可以

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

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

      2. 对于每个间隔执行:

        sum[ai]++;

        sum[bi+1]--;

      //这一步的总复杂度是O(N),因为我们在O(1)中处理每个区间。

      1. 聚合:

        for (int i = 1; i

      //这是一个O(N)步。

      1. 找到 sum[k] 最大的位置 k。
      2. 迭代新区间 [ai, bi] 并找到第一个包含位置 k 的区间(即 ai

      这个区间 [ai, bi] 是一个解,它与所有其他区间相交的次数是“sum[k] - 1”(不考虑自身)。

      【讨论】:

        【解决方案5】:

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

        1. 创建一个包含 N 个值的数组 A,其中 N 大于 max(bi)
        2. 将数组中的所有值清零
        3. 循环遍历区间并更改 A[ai]:=A[ai]+1, A[bi+1]:=A[bi+1]-1
        4. 设置 x=0
        5. 遍历数组计算 x:=x+A[j],寻找 x 的最大值

        在迭代 j 处 x 的值给出了与点 j 相交的区间数,因此找到最大值给出与最多区间相交的点。

        这需要 O(N+n) 个周期,因此仅当 n>N 对您的应用程序有用。

        (严格来说,这并不能回答问题,因为它会找到最相交的点。但是,您应该能够扩展这种方法以找到最相交的区间。)

        【讨论】:

          【解决方案6】:

          你可以在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)
          

          【讨论】:

          • 我认为您应该选择其中一个范围,而不是定义一个新范围。
          • 为什么?他说的是“找到范围”,而不是“扩大范围以包括新范围”。
          猜你喜欢
          • 1970-01-01
          • 2019-02-14
          • 2019-11-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多