Python:检查重叠范围的复杂性

时间:2018-01-04 13:04:38

标签: python algorithm time-complexity

我有两个范围,想要检查它们是否在Python(v3.5)中重叠。这些是一些解决方案。

1a :使用范围:

的集合intersection
def overlap_intersection_set(range1, range2):
  return bool(set(range1).intersection(range2))

1b :将set intersection与两套使用:

def overlap_intersection_two_sets(range1, range2):
  return bool(set(range1).intersection(set(range2)))

2 :使用any和范围in

def overlap_any(range1, range2):
  return any([i1 in range2 for i1 in range1])

我一直在努力计算这些方法的成本,主要是在时间方面,但空间复杂性也可能相当大。

设置交叉点的Python Wiki page "Time Complexity"列表(平均大小写):

  

交叉点s& t(平均情况):O(min(len(s), len(t))(替换" min"用" max"如果t不是一组)

对于解决方案 1b ,我因此假定O(min(len(range1), len(range2)),加上两次来自范围的集合创建。我认为bool函数非常便宜。

对于解决方案 1a O(max(len(range1), len(range2)),再加上一次从范围创建的设置。

对于解决方案 2 any):我没有找到很多关于复杂性的文档,无论是any还是范围in。对于后者,我假设范围的行为类似于列表,这对于每个O(n)调用意味着in,因此导致O(n*m)n=len(range1)和{{1} }。同时,只要找到匹配项,m=len(range2)就会生成快捷方式,并且可以节省集合创建。

因此,我的问题涉及算法复杂性以及它们特定于Python的实现:

  1. 将范围转换为集合的费用是多少?
  2. any功能真的有多贵?
  3. 某个范围的bool()是否真的与列表中的行为相同(in)?
  4. 除了算法复杂性之外还有哪些其他实现细节?
  5. 最后,考虑到这些问题:检查两个范围之间重叠的最有效方法是什么?
  6. 这并不容易根据经验进行评估,因为实际计算时间很大程度上取决于范围的属性,即找到重叠元素的早期及其大小。这就是为什么我在寻找更具分析性的解释。

1 个答案:

答案 0 :(得分:1)

不要这样做。代替:

  1. 安排每个范围排列为从最低到最高。
  2. 如果range1.lowest> range2.lowest然后将range1与range2
  3. 交换
  4. 如果range1.highest> range2.lowest然后范围相交
  5. 如果range1.highest == range2.lowest则触摸范围
  6. 如果range1.highest< range2.lowest则范围是不同的。
  7. 上述算法独立于范围的大小,也可以处理非整数范围。

    类似的东西:

    def is_overlapped(r1, r2):
        if r1.lowest > r2.lowest:
            r1, r2 = r2, r1
        return r1.highest > r2.lowest
    

    更全面的实施:

    from collections import namedtuple
    
    class Range(namedtuple('Range', 'lowest, highest')):
    
        __slots__ = () 
    
        def __new__(_cls, lowest, highest):
            'Enforces lowest <= highest'
            if lowest > highest:
                lowest, highest = highest, lowest
            return super().__new__(_cls, lowest, highest)
    
    def is_overlapped(r1, r2):
        r1, r2 = sorted([r1, r2])
        return r1.highest > r2.lowest
    
    if __name__ == '__main__':
        range1, range2 = Range(4, -4), Range(7, 3)
        assert is_overlapped(range2, range1) == is_overlapped(range1, range2)
        print(is_overlapped(range2, range1))  # True