Lesson 40 / 42
Intervals
Merging overlaps and scheduling non-overlapping intervals — both start with sorting.
Sort first, always
Almost every interval problem starts by sorting intervals by start time (or end time for scheduling). Once sorted, overlaps and gaps become adjacent comparisons instead of an all-pairs search.
Merge overlapping intervals
After sorting by start, walk through and merge whenever the current interval's start is <= the last merged interval's end.
def merge(intervals):
intervals.sort(key=lambda x: x[0])
merged = [intervals[0]]
for start, end in intervals[1:]:
last_end = merged[-1][1]
if start <= last_end:
merged[-1][1] = max(last_end, end)
else:
merged.append([start, end])
return merged
Output:
merge([[1,3],[2,6],[8,10],[15,18]]) # [[1,6],[8,10],[15,18]]
Interval scheduling (max non-overlapping)
To fit the most non-overlapping intervals, sort by end time and greedily keep an interval whenever it starts after the last kept interval's end.
def max_non_overlapping(intervals):
intervals.sort(key=lambda x: x[1])
count, last_end = 0, float('-inf')
for start, end in intervals:
if start >= last_end:
count += 1
last_end = end
return count
Output:
max_non_overlapping([[1,2],[2,3],[3,4],[1,3]]) # 3
Common variants
Insert a new interval into a sorted list, find minimum meeting rooms needed (use a heap of end times), and check if a person can attend all meetings — all built on the same sort-then-scan idea.