在给定两个区间列表的情况下,得到重叠区间的数量

get the number of overlapping intervals, given two lists of intervals

本文关键字:区间 情况下 重叠 列表 两个      更新时间:2023-10-16

我最近遇到了一个有趣的问题:

给定两个区间列表,从这两个列表中找出重叠区间的总数。

Example
L1: ([1,2][2,3][4,5][6,7])
L2: ([1,5][2,3][4,7][5,7])
[1,5] overlaps [1,2] [2,3] [4,5]
[2,3] overlaps [1,2] [2,3]
[4,7] overlaps [4,5] [6,7]
[5,7] overlaps [4,5] [6,7]
total = 3+2+2+2 = 9

显然,蛮力方法是有效的,但它太慢了(我需要比O(n^2)更好的方法)。

我也喜欢这里类似的问题。但这并不完全一样。。。

感谢提供的任何帮助

用成对的(value; +1 or -1 for start and end of interval)生成两个排序列表。

两个计数器—Count1Count2,显示第一个和第二个列表中的活动间隔数。

以合并方式浏览这两个列表。

当您从第一个列表中获得配对时,带有+1-增量Count1

当您从第一个列表中获得具有-1的配对时,递减Count1并将Count2添加到结果中

第二个列表中的对也是如此

最后阶段的伪代码

CntA = 0
CntB = 0
Res = 0
ia = 0
ib = 0
while (ia < A.Length) and (ib < B.Length)
if Compare(A[ia], B[ib]) <= 0
CntA = CntA + A[ia].Flag
if (A[ia].Flag < 0)
Res = Res + CntB
ia++
else
CntB = CntB + B[ib].Flag
if B[ib].Flag < 0
Res = Res + CntA
ib++

微妙时刻——比较if Compare(A[ia], B[ib]) <= 0在这里,我们还应该考虑标志-正确处理端点只接触[1.2][2..3]的情况(您将这种情况视为相交)。所以排序和合并比较器都应该取这样的合成值:3 * A[ia].Value - A[ia].Flag。通过这种比较,区间的起始点在区间结束前用相同的坐标进行处理。

p.S.在Delphi中进行了快速测试。适用于给定的数据集和一对其他数据集。

Delphi代码(ideone FPC由于泛型原因没有编译它)

尝试寻找扫描线算法,它将为您提供最快的解决方案。

您可以在TopCoder网站查看简短描述,或观看Robert Sedgwick的视频。这些描述了一个更难的问题,但应该给你一个如何解决你的问题的方法。

实际上,主要的想法是每次更新特殊交叉列表中的分段列表时,遍历分段的开始和结束的排序列表。

对于此任务,每个原始列表将分别有两个交集列表。开始时,两个交叉点列表都为空。当越过线段的起点时,将其添加到适当的交叉点列表中,它显然与其他交叉点列表的所有线段相交。当到达线段的末端时,只需将其从交点列表中删除即可。

这个算法将给你O(n log(n))的速度,在最坏的情况下,O(n)的内存。

您可以在第二个数组上的循环中使用std::set_intersection来将其与第一个数组中的每个项匹配。但我不确定性能是否符合你的要求。

我最近在处理一个类似的问题时偶然发现了区间树ADT——我怀疑它对您有用,无论您是否实现它。

它基本上是一个三元树,我用包含以下内容的节点构建了它:

  • 包含小于当前节点的间隔的左子树
  • 包含超过当前节点的间隔的右侧子树
  • 重叠间隔列表
  • 包含所有重叠区间的区间值

O(n*log(n))中构建树后,用于检查重叠间隔的查询函数应为O(log(n) + m),其中m是报告的重叠间隔数。

注意在创建时,按间隔中的结束值排序和拆分列表应该有助于保持平衡。