结合交叉间隔

时间:2012-09-10 17:06:01

标签: java algorithm intervals

  

可能重复:
  Union of intervals
  how to overlap intervals efficiently

给定一个间隔列表表示所有整数,如果它们相交或重叠,应该可以将它们折叠成一个间隔,否则给定的间隔不受影响。 比如,如果输入是例如I [(2-6),(1-4),(8-12)],则预期输出为[(1-6),(8-12)] 例如II [(4-7),(2-6),(1-4),(8-12),(7-9)]预期输出为[(1-12)]。

更正:错过了排序部分,所以是的,它是O(nlogn)时间而不是O(n)。感谢您指出了这一点。 我已经编写并测试了O(nlogn)时间和O(2n)空间算法方法。在下面分享这种方法的代码。我有兴趣听取解决这个问题的不同方法,可能更有效率。

//假设每个区间,(2-6)等表示为“区间”对象(下面显示的类定义),其中low = 2且high = 6 //步骤1:按给定间隔的低端点排序 // Step2:找到已排序区间的联合

//输入:

List<Interval> intervalList = new ArrayList<Interval>(); 

//输出:

List<Interval> unionList = new ArrayList<Interval>();    

private static final Comparator<Interval> Low_EPSorter = new LowEPSorter();

class Interval {
  int low, high;

  Interval(int l, int h, int m) {
    low = l;
    high = h;
  }
}

//// ------- BEGIN:找到给定间隔的联盟的方法---- //////

void UnionOfIntervals() {
  //Find intersection and combine intervals as necessary
  int sz = intervalList.size();

  // sort by low endpoint
  Collections.sort(intervalList, Low_EPSorter);

      for(int i = 0; i < sz; i++) {
        int j = i;
        if(j > 0) {
          if( Intervals.intersect(intervalList.get(j), intervalList.get(j-1)) ) {
            Interval v = union(intervalList.get(j), intervalList.get(j-1));
            checkAndAdd(v, unionList);
          }
          else {
            if(i == 1) {
              unionList.add(intervalList.get(j-1));
              unionList.add(intervalList.get(j));
          }
          else {
            unionList.add(intervalList.get(j));
          }
        } //No intersection
      } //If 2 elements atleast
      }

      //Print intervals after union
      System.out.println("Input intervals after sorting:");
      for(Interval v : intervalList) {
        System.out.print(v.low + "," + v.high + " ");
      }
      System.out.println();
      System.out.println("Union of intervals:");
      for(Interval v : unionList) {
        System.out.print(v.low + "," + v.high + " ");
      }
    }

    void checkAndAdd(Interval x, List t) {
      int top = t.size()-1;
      if( top >=0 && Intervals.intersect(unionList.get(top), x) ) {
        Interval v = union(unionList.get(top), x);
        t.remove(top);
        t.add(v);
      }
      else {
        t.add(x);
      }
    }

//// ------- END:查找给定间隔的联合的方法---- //////

//// ---帮助方法--- ////

static boolean intersect(Interval a, Interval b) {
      boolean r = false;
      if(b.high < a.low || b.low > a.high)
        r = false;
      else if(a.low <= b.high && b.low <= a.high)
        r = true;
      return r;
}

Interval union(Interval a, Interval b) {
      int l = (a.low < b.low) ? a.low : b.low;
      int max = (a.high > b.high) ? a.high : b.high;
      return new Interval(l, max);
}

private static class LowEPSorter implements Comparator<Interval> {

      public int compare(Interval a, Interval b) {
        int r = 0;
        if(a.low < b.low)
          r = -1;
        else if(a.low > b.low)
          r = 1;
        return r;
      }

}

4 个答案:

答案 0 :(得分:1)

取一个大小为n的数组(其中n是最大数字),并分别用1和-1填充间隔的开始和结束。

我的意思是,如果间隔是

{[1-4],[6-8]} 

然后数组元素就像

array[1]=1,array[4]=-1,array[6]=1,array[8]=-1

其余数组的所有其他位置都将设置为零。

现在遍历数组并通过扫描数组我们可以获得间隔,就像

一样
{[1-4],[2-5],[7-9]},

首先如上所述填充数组,数组A看起来像(假设起始索引为1):

A=[1,1,0,-1,-1,0,1,0,1]

现在从头开始遍历数组A,取一个变量sum = 0,并将存储在数组位置的值加到sum。

说明数组的每个索引的总和:

在位置1:sum = 1(索引1处为1)

在位置2:sum = 2(索引2处为1)

在位置3:sum = 2(索引3处为0)

在位置4:sum = 1(索引4处为-1)

在位置5:sum = 0(索引5处为-1)

现在总和达到零,这意味着一个间隔在这里结束,所以新的间隔将是[1-5]

在位置6:sum = 0(索引6处为0)

在位置7:sum = 1(索引7处为1)

(在位置7,总和再次变为大于零,这意味着间隔刚刚开始)

在位置8:sum = 1(索引8处为0)

在位置9:sum = 0(索引9处为-1)

间隔从刚刚结束的位置7开始,因此新的间隔范围将是

{[1-5],[7-9]}

希望它有所帮助。

答案 1 :(得分:0)

如果您正在为此问题寻找比O(n)更高效的算法,我不相信您会找到它。无论您使用什么数据结构存储初始间隔值,最糟糕的情况是没有任何间隔重叠,您必须检查每个间隔以确认这一点,因此O(n)。即使使用HashMap和非常精细的密钥结构,您仍然可以查看O(n)。

有了这个说法,我不确定是否有任何其他方法值得研究,因为你已经找到了一个在最佳时间内解决它的算法,O(n)。

答案 2 :(得分:0)

只是一个想法:管理一组不相交的间隔。从空集开始,添加传入间隔。如果新间隔与一个或两个现有间隔相交,请将它们组合。要计算交叉点,请使用2个TreeMaps引用同一组间隔,但使用不同的键:低限和高限。

答案 3 :(得分:0)

另一个想法:

  • 使用Bool数组
    • 默认情况下将所有值设为false
    • 对于所有间隔(在输入中)使值为true
    • 扫描更新的阵列并获得最终的交叉结果。