Python - 过滤重叠范围

时间:2012-07-10 12:55:00

标签: python algorithm python-2.7

我有一张{integer_key -> list[tuple]}的地图作为键/值对。元组包含(start,end)个值,表示子字符串操作的字符串索引。

我的目标是删除重叠区域并返回键/值对为{tuple -> integer_key}的地图。 映射到较低integer_keys的范围优先于较高的范围。

下面是我当前实现的可运行示例(需要此ordereddict类):

from collections import OrderedDict

string_length = 20

idx_region_map = OrderedDict()
idx_region_map[0] = [(0,2), (7,10)]
idx_region_map[1] = [(4,5), (18,19)]
idx_region_map[2] = [(3,3), (5,6), (10,13)]
idx_region_map[3] = [(15,17), (19,20)]

# Which can be represented as follows:
#
#  |012345678901234567890|
# 0|ooo----oooo----------|
# 1|----oo------------oo-|
# 2|---o-oo---oooo-------|
# 3|---------------ooo-oo|
# ...

def filter_overlaps(string_length, idx_region_map):
    region_idx_map = {}
    occupied = [False for i in range(string_length)]
    for idx, regions in idx_region_map.items():
        for region in regions:
            start, end = region[0], region[1] + 1
            overlaps = any(occupied[start:end])

            if not overlaps:
                for i in range(start, end):
                    occupied[i] = True
                region_idx_map[region] = idx
    return region_idx_map


# Prints: {(3, 3): 2, (4, 5): 1, (18, 19): 1, (7, 10): 0, (0, 2): 0, (15, 17): 3}
print filter_overlaps(string_length, idx_region_map)

这似乎足以满足我的需求,但我很想知道有哪些替代算法可以解决这个问题。例如,使用不同的数据结构或比上述更有效的东西。

2 个答案:

答案 0 :(得分:2)

您可以使用Interval tree

我不懂Python,但我认为你在这里做蛮力。

另一种方法是根据起始索引进行排序;所以对你而言,你得到了

0 3 4 5 7 10 15 18 19

现在浏览每个起始索引,并通过二进制搜索检查其对应的结束索引在起始索引之后的位置,即此处我们取0,得到它的结束索引为2并查看2所在的位置。因为2位于0之后,它不会重叠任何东西,但是让我们说0的结束指数是17然后它意味着0,17重叠所有起始指数直到15,这是3,4,5,7,10,15。复杂性是nlogn。

修改

我刚刚意识到你保留了4,5虽然4,5和5,6重叠,我猜因为4,5整数键是1,它小于5,6的整数键,即2。所以我猜你总是保留较低的整数键,虽然它是重叠的。

如果是这种情况,复杂性将为O(n ^ 2),因为您不能盲目地进行二分查找。对于例如如果4的结束索引是10,那么你将不得不通过5,7和10检查它们的整数键是否小于4。如果它是4,则可以过滤其结束索引,否则保留4。

答案 1 :(得分:0)

而不是occupied = [False]*string_length您可以维护一个数据结构,该数据结构存储到目前为止看到的非重叠范围并支持.overlaps(start, end)操作:

def overlaps(self, start, end):
    # invariant: all stored intervals do not overlap
    # perform binary search on non-overlapping intervals O(log n)
    # if overlaps; merge with stored intervals O(m)
    # else store (start, end) O(1)
    # return whether (start, end) overlaps with already seen intervals

复杂性为O(log n + m),其中n - 存储间隔数,m - 与给定范围重叠的间隔数。

如果string_length不大,你的算法就好了。

相关问题