我有一个元组列表,我用它来标记范围的下限和上限。例如:
[(3,10), (4,11), (2,6), (8,11), (9,11)] # 5 separate ranges.
我想找到三个或更多输入范围重叠的范围。例如,上面列出的元组将返回:
[(4,6), (8,11)]
我尝试了@WolframH提供的方法来回答这个post
但我不知道我能做些什么:
给我多个输出范围
设置至少三个范围重叠的阈值以限定输出
答案 0 :(得分:1)
首先必须找到范围的所有组合。然后你可以将它们转换成集合并计算交集:
import itertools
limits = [(3,10), (4,11), (2,6), (8,11), (9,11)]
ranges = [range(*lim) for lim in limits]
results = []
for comb in itertools.combinations(ranges,3):
intersection = set(comb[0]).intersection(comb[1])
intersection = intersection.intersection(comb[2])
if intersection and intersection not in results and\
not any(map(intersection.issubset, results)):
results = filter(lambda res: not intersection.issuperset(res),results)
results.append(intersection)
result_limits = [(res[0], res[-1]+1) for res in map(list,results)]
它应该给你所有3个明智的交叉点
答案 1 :(得分:0)
当然,您可以通过强力检查所有组合来解决这个问题。但是,如果您需要此算法进行缩放,则可以在(伪)nlogn中执行此操作。从技术上讲,你可以提出一个退化的最坏情况,即O(n ** 2),但是什么是人。
基本上,您对范围进行排序,然后对于给定范围,您可以查看其立即左侧以查看边界是否重叠,如果是,则查看正确将重叠间隔标记为结果。伪代码(实际上几乎是有效的python,看看):
ranges.sort()
for left_range, current_range, right_range in sliding_window(ranges, 3):
if left_range.right < current_range.left:
continue
while right_range.left < min(left_range.right, current_range.right):
results.append(overlap(left_range, right_range))
right_range = right_range.next
#Before moving on to the next node, extend the current_range's right bound
#to be the longer of (left_range.right, current_range.right)
#This makes sense if you think about it.
current_range.right = max(left_range.right, current_range.right)
merge_overlapping(results)
(你还需要在最后合并一些可能重叠的范围,这是另一个nlogn操作 - 虽然那里的n通常会小得多。我不会讨论代码,但是它&#39;与上述方法类似,涉及排序然后合并。See here for an example。)