从区间列表中高效地找到重叠的区间

4

这与查找重叠区间有关。我知道如何在给定的区间列表(区间树)中执行此操作。但是我现在手头上有一个区间列表的列表。例如:

[2,6], [7,11]
[1,3], [5,10], [11,13]
[2,5], [6,8]

这个问题的结果应该是

[2,3], [7,8]

我需要做的是找到在所有列表中都共有的区间列表。

我认为这个问题类似于合并 n 个列表。但问题是,我不能对列表进行成对合并。这种方法可能会导致重叠区间的丢失。因此,我需要同时考虑所有列表来合并它们(而不是成对)。

我可以使用区间树。将每个列表的第一个区间插入到区间树中,并找到重叠部分。从树中移除最弱的区间,并插入其中一个列表的下一个区间。我还没有完全弄清楚如何使用这种方法,但似乎这将变得太昂贵了。

有没有有效的算法来从区间的列表列表中找到重叠的区间?

其他信息:

列表内的区间已排序。 它们不重叠并形成一个序列。

3个回答

4
创建一个单一的、排序的过渡数组。每个过渡都有一个位置和一个累积数字,该数字基于你加入或离开了多少个区间。当你通过列表时,跟踪你所在的区间数量。当你在与系列相同数量的区间中时,这就是你处于公共区间的时候。
对于你的示例,过渡将如下所示:
[2, 1], [6, -1], [7, 1], [11, -1],
[1, 1], [3, -1], [5, 1], [10, -1], [11, 1], [13, -1]
[2, 1], [5, -1], [6, 1], [8, -1]

经过按位置排序和合并后,变成了:

[1, 1], [2, 2], [3, -1], [5, 0], [6, 0], [7, 1], [8, -1], [10, -1], [11, 0], [13, -1]

这提供了关于以下内容的运行总计的转换:

[1, 1], [2, 3], [3, 2], [7, 3], [8, 2], [10, 2], [13, 1]

然后,我们可以读取在3处的间隔,其中一个从2开始到3,另一个从7开始到8。这就是答案。
创建一个长列表并进行排序的想法确实需要额外的工作量。你可以在运行时创建这些列表并将它们合并。节省的代价是系列数的对数而不是事件数的对数。

很抱歉,但是我在“which gives you transitions for running totals of”这句话就跟丢了。您能否再详细解释一下?谢谢! - akaHuman
1
第一个条目保持位置不变。第二个是到该点的更改总和。因此,我们从[1, 1]开始,然后是[2, 1+2],然后是[2, 1+2-1]等等(因为更改遵循1、2、-1、0、0、1、-1、-1、0、-1)。0转换无关紧要,所以我将它们删除了。 - btilly

2

您说每个间隔列表都是排序的且不重叠。因此,

Keep track of where you are in each list, starting at the beginning of each.
While none of the lists has run out:
    If the current intervals (one from each list) all overlap:
       Output the intersection of the current intervals
    Find which of the current intervals has the earliest end point
    Advance one position within that list.

如果有K个区间列表和总共N个区间,如果最直接的方法实现,这将需要O(N K)的时间,但是你应该能够通过在堆或其他优先队列中跟踪当前区间的信息来将其减少为O(N log K)的时间。

2

我理解您想要做的是对区间列表应用交集操作。您可以成对进行此操作,因为交集是可结合的。

我会做类似以下的操作:

Let S be the set of sets, R = s1, s1 in S
     for each set s2 in S / {s1}
              for each element e1 in R
                  for each element e2 in s2 s.t. e1.sup < e2.inf
                    e1 <- intersection (e1, e2)

两个区间的交集操作是

 intersection (e1,e2):
    return new Interval(max(e1.inf, e2.inf), min (e1.sup, e2.sup));

这不过是一种暴力解决方案罢了!如果我找到更高效的解决方案的话,我会非常期待它。 - akaHuman
是的,它是O(n)的。如果你的集合是有序的,平均情况下可以做得更好(只要在遇到一个元素e2,其下限高于第二个元素的上限时立即退出第二个循环就可以了)。刚刚编辑过伪代码。 - hpid91

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接