间隔联盟

时间:2009-06-23 19:55:49

标签: union intervals

我有一个代表间隔的班级。该类具有可比类型的两个属性“start”和“end”。现在我正在寻找一种有效的算法来结合一组这样的区间。

提前致谢。

6 个答案:

答案 0 :(得分:13)

按照其中一个术语(例如,开始)对它们进行排序,然后在列表中移动时检查与其(右手)邻居的重叠。

class tp():
    def __repr__(self):
        return '(%d,%d)' % (self.start, self.end)
    def __init__(self,start,end): 
        self.start=start
        self.end=end
s=[tp(5,10),tp(7,8),tp(0,5)]
s.sort(key=lambda self: self.start)
y=[ s[0] ]
for x in s[1:]:
  if y[-1].end < x.start:
      y.append(x)
  elif y[-1].end == x.start:
      y[-1].end = x.end

答案 1 :(得分:4)

使用sweep line算法。基本上,您对列表中的所有值进行排序(同时保持区间的开始或结束以及每个项目)。该操作是O(n log n)。然后沿着已排序的项循环一次,并计算间隔O(n)。

O(n log n)+ O(n)= O(n log n)

答案 2 :(得分:3)

geocar算法在以下情况下失败:

s=[tp(0,1),tp(0,3)]

我不太确定,但我认为这是正确的方法:

class tp():
    def __repr__(self):
        return '(%.2f,%.2f)' % (self.start, self.end)
    def __init__(self,start,end): 
        self.start=start
        self.end=end
s=[tp(0,1),tp(0,3),tp(4,5)]
s.sort(key=lambda self: self.start)
print s
y=[ s[0] ]
for x in s[1:]:
    if y[-1].end < x.start:
        y.append(x)
    elif y[-1].end == x.start:
        y[-1].end = x.end
    if x.end > y[-1].end:
        y[-1].end = x.end
print y

我也用它来实现减法:

#subtraction
z=tp(1.5,5) #interval to be subtracted
s=[tp(0,1),tp(0,3), tp(3,4),tp(4,6)]

s.sort(key=lambda self: self.start)
print s
for x in s[:]:
    if z.end < x.start:
        break
    elif z.start < x.start and z.end > x.start and z.end < x.end:
        x.start=z.end
    elif z.start < x.start and z.end > x.end:
        s.remove(x)
    elif z.start > x.start and z.end < x.end:
        s.append(tp(x.start,z.start))
        s.append(tp(z.end,x.end))
        s.remove(x)
    elif z.start > x.start and z.start < x.end and z.end > x.end:
        x.end=z.start
    elif z.start > x.end:
        continue

print s

答案 3 :(得分:3)

事实证明,这个问题已经解决了很多次 - 在不同程度的幻想中,在命名法下:http://en.wikipedia.org/wiki/Interval_treehttp://en.wikipedia.org/wiki/Segment_tree以及'RangeTree'

(因为OP的问题涉及这些数据结构很重要的大量间隔时间)


就我自己选择的python库选择而言:

  • 从测试开始,我发现大多数关于全功能和python当前(非位腐烂)的内容:来自SymPy的'Interval'和'Union'类,请参阅:{{ 3}}

  • 另一个好看的选择,更高的性能但功能更少的选项(例如,不适用于浮点范围删除):http://sympystats.wordpress.com/2012/03/30/simplifying-sets/

最后:在任何IntervalTree,SegmentTree,RangeTree下搜索SO本身,你会发现更多的答案/钩子

答案 4 :(得分:1)

对所有点进行排序。然后通过列表递增“开始”点的计数器,并将其递减为“结束”点。如果计数器达到0,那么它实际上是联合中一个区间的终点。

计数器永远不会变为负数,并且会在列表末尾达到0。

答案 5 :(得分:0)

在c ++中找到间隔联合的总和

#include <iostream>
#include <algorithm>

struct interval
{
    int m_start;
    int m_end;
};

int main()
{
    interval arr[] = { { 9, 10 }, { 5, 9 }, { 3, 4 }, { 8, 11 } };

    std::sort(
        arr,
        arr + sizeof(arr) / sizeof(interval),
        [](const auto& i, const auto& j) { return i.m_start < j.m_start; });

    int total = 0;
    auto current = arr[0];
    for (const auto& i : arr)
    {
        if (i.m_start >= current.m_end)
        {
            total += current.m_end - current.m_start;
            current = i;
        }
        else if (i.m_end > current.m_end)
        {
            current.m_end = i.m_end;
        }
    }

    total += current.m_end - current.m_start;
    std::cout << total << std::endl;
}