得到两个间隔列表,得到重叠间隔的数量

时间:2016-05-20 13:58:43

标签: c++ algorithm

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

给定两个间隔列表,找到两个列表中的重叠间隔总数。

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)更好的东西)。

我也喜欢类似的问题here。但它并不完全一样......

感谢任何帮助

4 个答案:

答案 0 :(得分:3)

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

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

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

对于此任务,您将分别为每个原始列表分别有两个交叉点列表。在开始时,两个交叉点列表都是空的。在越过段的开头时,将其添加到适当的交叉点列表,它显然与另一个交叉点列表中的所有段相交。当到达段的末尾时,只需将其从交叉点列表中删除。

此算法将为您提供O(n log(n))速度,最坏情况下为O(n)内存。

答案 1 :(得分:3)

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

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

以合并方式遍历两个列表。

当您从第一个列表中获得+1时加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 code(由于仿制药,FPC没有编译它)

答案 2 :(得分:0)

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

答案 3 :(得分:0)

我最近在处理类似问题时偶然发现了Interval Tree ADT - 我怀疑它对你有用,无论你是否实现它。

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

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

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

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