Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding longest overlapping ranges [duplicate]

I have ranges in a list like:

ranges = [(1, 50), (49, 70), (75, 85), (84, 88), (87, 92)] 

I would like to find the longest ranges that can be constructed from these (when they overlap with each other).

Expected output:

[(1, 70), (75, 92)] 

I have a solution, however it is way too complicated, and I am sure there must be an easier solution to this problem

My solution:

def overlap(x, y):     return range(max(x[0], y[0]), min(x[-1], y[-1]) + 1)  ranges = [(1, 50), (49, 70), (75, 85), (84, 88), (87, 92)]  beg, end = min([x[0] for x in ranges]), 0 for i in ranges:     if i[0] == beg:         end = i[1] while beg:     for _ in ranges:         for i in ranges:             if i[1] > end and overlap(i, [beg, end]):                 end = i[1]     print(beg, end)     try:         beg = min([x[0] for x in ranges if x[0] > end])         for i in ranges:             if i[0] == beg:                 end = i[1]     except ValueError:         beg = None 

Output:

1 70 75 92 
like image 952
Gábor Erdős Avatar asked Dec 17 '19 14:12

Gábor Erdős


People also ask

How do you find overlapping ranges?

1) Sort all intervals in increasing order of start time. This step takes O(nLogn) time. 2) In the sorted array, if start time of an interval is less than end of previous interval, then there is an overlap.

What does it mean when ranges overlap?

If both ranges have at least one common point, then we say that they're overlapping. In other words, we say that two ranges and are overlapping if: On the other hand, non-overlapping ranges don't have any points in common.


1 Answers

I think you can sort your input by the start of the ranges, then iterate through them. At each item, it is either added to the current range (if the start is less than the end of the current range) or we yield out current range and begin accumulating a new range:

def overlaps(ranges):     ranges = sorted(ranges)  # If our inputs are garunteed sorted, we can skip this     it = iter(ranges)     try:         curr_start, curr_stop = next(it)         # overlaps = False  # If we want to exclude output ranges not produced by overlapping input ranges     except StopIteration:         return     for start, stop in it:         if curr_start <= start <= curr_stop:  # Assumes intervals are closed             curr_stop = max(curr_stop, stop)             # overlaps = True         else:             # if overlaps:             yield curr_start, curr_stop             curr_start, curr_stop = start, stop             # overlaps = False     # if overlaps:     yield curr_start, curr_stop  print(list(overlaps([(1, 50), (49, 70), (75, 85), (84, 88), (87, 92)]))) # [(1, 70), (75, 92)]  print(list(overlaps([(20, 30), (5, 10), (1, 7), (12, 21)]))) # [(1, 10), (12, 30)] 
like image 152
Patrick Haugh Avatar answered Oct 04 '22 14:10

Patrick Haugh