Reputation: 83
I am trying to implement the logic in python. Given a set of intervals, find the interval which has the maximum number of intersections. If input (1,6) (2,3) (4,11)
, then (1,6)
should be returned. This has been answered in below but I have been unable to implement it in python.
given-a-set-of-intervals-find-the-interval-which-has-the-maximum-number-of-inte.
So far I am using the below logic. Any help will be greatly appreciated.
def interval_intersection(intervals):
if len(intervals) ==1:
return intervals
intervals.sort(key=lambda x: x[0])
res =[intervals[0]]
for i in range(1,len(intervals)):
if intervals[i][0] > res[-1][1]:
res.append(intervals[i])
else:
res[-1] = [min(res[-1][0],intervals[i][0]),max(res[-1][1],intervals[i][1])]
return res
Examples
:
[[1,5],[5,10],[5,5]]
ans should be [5,5]
In case of tie [5,5] the interval with least number of elements . Here [5,5] has only 1 element in the range ie 5 hence the ans[[1,2],[3,5]]
no intersection return -1
Upvotes: 0
Views: 464
Reputation: 5409
This is a fairly straightforward implementation of David Eisenstat's algorithm. The only subtleties are:
def interval_solve(intervals: Sequence[Sequence[int]]) -> Union[Sequence[int], int]:
start_type = -1 # Assumes all intervals are closed
end_type = 1
events = [(s, start_type, i) for i, (s, e) in enumerate(intervals)]
events.extend((e, end_type, i) for i, (s, e) in enumerate(intervals))
events.sort()
inter_count: Dict[int, int] = {}
start_count = 0
stop_count = 0
for event_time, event_type, event_id in events:
if event_type == start_type:
start_count += 1
inter_count[event_id] = -(stop_count + 1)
else:
stop_count += 1
inter_count[event_id] += start_count
# Find max by most intersections, then by shortest interval, then by earliest start
answer = max(range(len(intervals)),
key=lambda j: (inter_count[j], intervals[j][0] - intervals[j][1]))
if inter_count[answer] == 0:
return -1
return intervals[answer]
Upvotes: 2
Reputation: 11198
The actual idea is pretty simple, we sort the intervals and store some of them with an index and a boolean key for indicating the start or end events.
Then, we just traverse it while counting the end events before an index and the start events. For any index i
, interval overlap count is simply, number of start events before - number of end events before (-1).
Finally, we can just check which one has the minimum length in case of multiple solutions.
# https://stackoverflow.com/questions/69426852/max-interval-intersection-point
def max_interval_count(intervals):
interval_sorted = []
for idx, interval in enumerate(intervals):
s, e = interval
interval_sorted.append([s, idx, 0]) # 0 for start
interval_sorted.append([e, idx, 1]) # 1 for end
interval_sorted.sort(key = lambda x: x[0])
print(interval_sorted)
number_of_starts = 0
number_of_ends = 0
overlap_count = {}
for event in interval_sorted:
_, idx, start_end = event
if start_end == 0: # start event
# subtract all the ending before it
overlap_count[idx] = - (number_of_ends)
number_of_starts += 1
else: # end event
overlap_count[idx] += (number_of_starts - 1) # -1 as we should not include the start from the same interval
number_of_ends += 1
print(overlap_count)
ans_idx = -1
max_over_count = 0
min_len_interval = 99999999999
for idx, overl_cnt in overlap_count.items():
if overl_cnt > max_over_count:
ans_idx = idx
max_over_count = overl_cnt
elif overl_cnt == max_over_count and overl_cnt > 0 and (intervals[idx][1] - intervals[idx][0] + 1) < min_len_interval:
min_len_interval = (intervals[idx][1] - intervals[idx][0] + 1)
ans_idx = idx
if ans_idx == -1:
return ans_idx
return intervals[ans_idx]
if __name__ == "__main__":
test_1 = [[1,5],[5,10],[5,5]]
test_2 = [[1,2],[3,5]]
test_3 = [(1,6), (2,3), (4,11)]
ans = max_interval_count(test_1)
print(ans)
print("---------")
ans = max_interval_count(test_2)
print(ans)
print("---------")
ans = max_interval_count(test_3)
print(ans)
print("---------")
[[1, 0, 0], [5, 0, 1], [5, 1, 0], [5, 2, 0], [5, 2, 1], [10, 1, 1]]
{0: 0, 1: 1, 2: 1}
[5, 5]
---------
[[1, 0, 0], [2, 0, 1], [3, 1, 0], [5, 1, 1]]
{0: 0, 1: 0}
-1
---------
[[1, 0, 0], [2, 1, 0], [3, 1, 1], [4, 2, 0], [6, 0, 1], [11, 2, 1]]
{0: 2, 1: 1, 2: 1}
(1, 6)
---------
Upvotes: 1