合并两个已排序的间隔列表

时间:2018-03-31 02:50:03

标签: algorithm intervals overlap interval-tree

给定AB,这是两个间隔列表。 AA没有重叠,B B内没有重叠。在A中,间隔按其起点排序。在B中,间隔按其起点排序。如何合并两个间隔列表并输出结果而没有重叠?

一种方法是连接两个列表,按起点排序,并应用https://www.geeksforgeeks.org/merging-intervals/中讨论的合并间隔。有更有效的方法吗?

以下是一个例子:

A: [1,5], [10,14], [16,18]
B: [2,6], [8,10], [11,20]

输出:

[1,6], [8, 20]

3 个答案:

答案 0 :(得分:2)

因此,您有两个带事件的排序列表 - 输入间隔和离开间隔。

合并这些列表,将当前状态保持为整数0,1,2(活动间隔计数)

Get the next coordinate from both lists 
If it is entering event
   Increment state
   If state becomes 1, start new output interval 
If it is closing event
   Decrement state
   If state becomes 0, close current output interval 

请注意,此算法类似于交叉点查找there

答案 1 :(得分:1)

一个简单的解决方案可能是,缩小所有元素,将它们放入一个集合中,对其进行排序,然后迭代以将注入元素转换为间隔。

可以为您的其他问题选择类似的方法,只需消除所有不同的值即可获得重叠。

但是 - 这种方法存在问题。

让我们定义一个班级间隔:

case class Interval (lower: Int, upper: Int) {    
    def deflate () : List [Int] = {(lower to upper).toList}
}

并使用它:

val e = List (Interval (0, 4), Interval (7, 12))
val f = List (Interval (1, 3), Interval (6, 8), Interval (9, 11))
放气:

e.map (_.deflate)
// res26: List[List[Int]] = List(List(0, 1, 2, 3, 4), List(7, 8, 9, 10, 11, 12))    
f.map (_.deflate)
// res27: List[List[Int]] = List(List(1, 2, 3), List(6, 7, 8), List(9, 10, 11))

:::结合了两个列表,这里有两个列表列表,这就是为什么我们必须展平结果,制作一个大列表:

(res26 ::: res27).flatten
// res28: List[Int] = List(0, 1, 2, 3, 4, 7, 8, 9, 10, 11, 12, 1, 2, 3, 6, 7, 8, 9, 10, 11)

使用distinct,我们删除重复项:

(res26 ::: res27).flatten.distinct
// res29: List[Int] = List(0, 1, 2, 3, 4, 7, 8, 9, 10, 11, 12, 6)

然后我们对它进行排序:

(res26 ::: res27).flatten.distinct.sorted
// res30: List[Int] = List(0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12)

所有在一个命令链中:

val united = ((e.map (_.deflate) ::: f.map (_.deflate)).flatten.distinct).sorted
// united: List[Int] = List(0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12)
//                                        ^ (Gap)   

现在我们必须找到像4到6之间的差距并返回两个不同的列表。 我们递归地通过输入列表l,并且如果元素来自比最后一个更大的sofar收集的元素1,我们将该元素收集到该sofar-list中。否则,我们将sofar收集的列表作为部分结果返回,然后将其余部分与当前元素的List拆分为新的sofar-collection。在开始时,sofar是空的,所以我们可以从第一个元素添加到该列表并用它分割尾部开始。

def split (l: List [Int], sofar: List[Int]): List[List[Int]] = l match {
  case Nil    => List (sofar)
  case h :: t => if (sofar.isEmpty) split (t, List (h)) else 
    if (h == sofar.head + 1) split (t, h :: sofar) 
    else sofar :: split (t, List (h))
}

// Nil is the empty list, we hand in for initialization
split (united, Nil) 
// List(List(4, 3, 2, 1, 0), List(12, 11, 10, 9, 8, 7, 6))

将列表转换为间隔将是一项微不足道的任务 - 采取第一个和最后一个元素,瞧!

但这种方法存在问题。也许你认识到,我重新定义了你的A:和B :(来自前一个问题)。在B中,我将第二个元素重新定义为5-8到6-8。因为其他,它会与A的0-4合并,因为4和5是直接邻居,那么为什么不将它们组合成一个大间隔呢?

但也许它应该以这种方式工作?对于以上数据:

split (united, Nil) 
// List(List(6, 5, 4, 3, 2, 1), List(20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8))

答案 2 :(得分:1)

这是一种不同的方法,本着回答重叠问题的精神。

<!--code lang=scala--> 
def findUnite (l1: List[Interval], l2: List[Interval]): List[Interval] = (l1, l2) match {
    case (Nil, Nil) => Nil
    case (as, Nil)  => as
    case (Nil, bs)  => bs
    case (a :: as, b :: bs) => {
             if (a.lower > b.upper) b :: findUnite (l1, bs)
        else if (a.upper < b.lower) a :: findUnite (as, l2)
        else if (a.upper > b.upper) findUnite (a.union (b).get :: as, bs)
        else                        findUnite (as, a.union (b).get :: bs)
    }
}

如果两个列表都为空 - 返回空列表。 如果只有一个为空,则返回另一个。 如果一个列表的上限低于另一个列表的下限,则无法进行统一,因此返回另一个列表并继续执行其余操作。 如果它们重叠,则不返回,但是递归地调用该方法,在更远的区间一侧进行统一,并且没有消耗较少的远距离区间。

union方法看起来类似于重叠方法:

<!--code scala--> 
case class Interval (lower: Int, upper: Int) {
    // from former question, to compare
    def overlap (other: Interval) : Option [Interval] = {
        if (lower > other.upper || upper < other.lower) None else
        Some (Interval (Math.max (lower, other.lower), Math.min (upper, other.upper)))
    }

    def union (other: Interval) : Option [Interval] = {
        if (lower > other.upper || upper < other.lower) None else
        Some (Interval (Math.min (lower, other.lower), Math.max (upper, other.upper)))
    }    
}

非重叠的测试是相同的。但是min和max已经改变了位置。

因此对于(2,4)(3,5),重叠是(3,4),联合是(2,5)。

lower   upper
_____________
    2    4 
    3    5 
_____________
min 2    4 
max 3    5 

最小/最大下限/上限表。

<!--code lang='scala'--> 
val e = List (Interval (0, 4), Interval (7, 12))
val f = List (Interval (1, 3), Interval (6, 8), Interval (9, 11))
findUnite (e, f)
// res3: List[Interval] = List(Interval(0,4), Interval(6,12))

现在对于上面棘手或不清楚的案例:

val e = List (Interval (0, 4), Interval (7, 12))
val f = List (Interval (1, 3), Interval (5, 8), Interval (9, 11))
findUnite (e, f)
// res6: List[Interval] = List(Interval(0,4), Interval(5,12))

0-4和5-8不重叠,因此它们形成两个不合并的结果。