在不相交的间隔的排序列表中插入间隔

时间:2011-12-19 16:49:57

标签: algorithm

我有一个不相交的间隔和间隔的排序列表,例如[(1,5),(10,15),(20,25)]和​​(12,27)。所以,(12,27)是间隔    我想将它们合并为一个不相交间隔的排序列表:[(1,5),(10,27)]。

3 个答案:

答案 0 :(得分:4)

伪:

list = ...
u = (12,27)
i = 0
newlist = []

while (max(list[i]) < min(u))  //add all intervals before intersection
  newlist.add(list[i++])
mini = i

while (min(list[i]) < max(u))  // skip all intersecting intervals
  i++
maxi = i

newlist.add((min(list[mini],u),max(list[maxi],u)) // add the new interval

while (i < list.length) // add remaining intervals
  newlist.add(list[i++])

return newlist

答案 1 :(得分:0)

你可以用图形模拟你的问题,实际上你的间隔是节点,如果它们有公共部分它们相互连接(例如(12,27)连接到(15,20))现在首先你应该找到连接的组件,然后在每个连接的组件中找到开始的最小值(例如10)和结束的最大值(例如25)。很高兴看到Interval Graphs

答案 2 :(得分:0)

这是我的非惯用scala解决方案,充满了变量。该解决方案看起来比它应该更长,因为我在列表上的附加和插入实现很差,只支持前置操作。

算法如下:

  1. 扫描以将间隔列表分成两个列表,这些列表与新间隔不重叠,并且与新间隔重叠。非重叠间隔是在新间隔之后或完全在新间隔之前开始的间隔。此外,如果我们要插入一个新的间隔,它将在低于它的最高间隔之后。在这个阶段,我们有一个重叠间隔列表和一个非重叠间隔列表。
  2. 如果没有重叠,那么新的间隔要么早于所有给定的间隔,要么在所有间隔之后,或者在两个间隔之间(仍然没有重叠)。
  3. 如果存在重叠,则将重叠间隔与新间隔合并。重叠间隔的开始是min(新间隔的开始,最小重叠间隔的开始)。我们可以类似地计算结束。现在将重叠间隔插入先前计算的位置。
  4. 以下是代码:

    object trial {
      val intervals1 = List((1, 2), (4, 6), (7, 8), (16, 17)))
      val intervals2 = List((1, 5), (10, 15), (20, 25)
    
      val newInterval1 = (11, 12)
      val newInterval2 = (12, 27)
    
      // Interval algo test.
      val result1 = Merge(intervals1, newInterval1)   // result1  : List((1,2), (4,6), (7,8), (11,12), (16,17))
      val result2 = Merge(intervals2, newInterval2)   // result2  : List[(Int, Int)] = List((1,5), (10,27))
      }
    
    object Merge{
      def append[T](list: List[T], el: T): List[T] = {
        (el :: list.reverse).reverse
      }
      def insert[T](list: List[T], pos: Int, elem: T): List[T] = {
        var newList = List.empty[T]
        val reversePos = list.length - pos
        list.reverse.zipWithIndex foreach {
          case(el, i) if i == reversePos => {
            newList = elem :: newList
            newList = el :: newList
          }
          case (el, i) => newList = el :: newList
        }
        newList
      }
    
      def apply(list: List[(Int, Int)], interval: (Int, Int)): List[(Int, Int)] = {
        val (min, max) = interval
        var newList = List.empty[(Int, Int)]
        // Store potentially overlapping stuff.
        var overlap = List.empty[(Int, Int)]
        // Maintain the position to begin merge.
        var posInsert = 0
        list.zipWithIndex foreach { case(intervalz, i) =>
          if (intervalz._2 < min) {
          // Does not overlap but an insert will be after the highest of these.
            posInsert = i
            newList = append(newList, intervalz)
          } else if (intervalz._1 > max) {
            // Does not overlap.
            newList = append(newList, intervalz)
          } else overlap = append(overlap, intervalz)
        }
        if (overlap isEmpty) {
          if (posInsert == 0) newList = interval :: newList
          else newList = insert(newList, posInsert + 1, interval)
        } else {
          // Start of new interval is the lower of the first overlap's start or the interval's start.
          val startOfInterval = Math.min(overlap.head._1, min)
          // Enf of interval is higher of last overlap's end or interval's end.
          val endOfInterval = Math.max(overlap.head._2, max)
          // Insert the merged interval after the highest interval smaller than the start of the new internval.
          if (posInsert == 0) newList = (startOfInterval, endOfInterval) :: newList
          else newList = insert(newList, posInsert + 1, (startOfInterval, endOfInterval))
        }
        newList
      }
    }
    

    它通过了这里提到的测试,是O(N)。

    EDIT。它的算法版本:

    intervals = [....]
    newInterval = (12, 27)
    newList = []
    overlappingList = []
    posInsert = 0
    i = 0
    
    while (i < intervals.size)
      if (intervals[i].max < newInterval.min)
        posInsert = i
        append(newList, intervals[i]) 
      else if (intervals[i].min > newInterval.max)
        append(newList, intervals[i])
      else
        append(overlappingList, intervals[i])
      i++
    
    if (overlap isEmpty)
      if (posInsert == 0) prepend(newList, newInterval)
      else insert(newList, posInsert + 1, newInterval)
    else
      start = Min(overlappingList[i].min, newInterval.min)
      end = Max(overlappingList[i].max, newInterval.max)
      if (posInsert == 0) prepend(newList, newInterval)
      else insert(newList, posInsert + 1, new Interval(start, end))
    return newList