10.1 Intervals (Sorting, Merging & Sweep Line)
Understand what an Interval is, why sorting by start time or end time is the universal first step, and how to merge or remove overlapping intervals.
1. What Is an Interval?
An Interval [start, end] is simply a pair of numbers representing a continuous span on a timeline — such as a calendar meeting from 1:00 to 4:00 ([1, 4]), a flight reservation, or a project schedule.
2. Why Do We Need Interval Sorting & How Does Overlap Work?
The Pain of Unsorted Intervals (O(N^2))
If someone gives you 10,000 meetings in random order and asks which meetings conflict, you would have to compare every meeting against every other meeting (O(N^2)).
How Sorting Unlocks a Single O(N) Pass
The moment you sort the intervals (O(N log N)), any overlapping intervals are guaranteed to sit right next to each other!
There are only two sorting strategies you need to know:
- Sort by
starttime (intervals.sort(key=lambda x: x[0])): Use this when merging or inserting intervals (Merge Intervals,Insert Interval). Oncea = [s1, e1]comes beforeb = [s2, e2](s1 <= s2), they overlap if and only ifs2 <= e1(the second interval starts before the first one finishes). Merge them into[s1, max(e1, e2)]! - Sort by
endtime (intervals.sort(key=lambda x: x[1])): Use this when choosing the maximum number of non-overlapping intervals (Non-overlapping Intervals). Why? Because keeping the meeting that finishes earliest frees up your room as soon as possible for future meetings!
Interactive Step-by-Step Trace: Sort by Start Time & Merge Overlaps
Merge [[1,3], [2,6], [8,10]]:
Because 2 starts before 3 ends, we stretch the end of [1, 3] to max(3, 6) = 6.
3. Basic Operations & Walkthroughs (All 4 Languages)
# 1. Merge Overlapping Intervals (Sort by START time) -> O(N log N)
def merge_intervals(intervals: list[list[int]]) -> list[list[int]]:
intervals.sort(key=lambda x: x[0])
merged = [intervals[0]]
for start, end in intervals[1:]:
if start <= merged[-1][1]: # Overlaps with previous interval!
merged[-1][1] = max(merged[-1][1], end)
else:
merged.append([start, end])
return merged
# 2. Minimum Removals to Eliminate Overlaps (Sort by END time) -> O(N log N)
def erase_overlap_intervals(intervals: list[list[int]]) -> int:
intervals.sort(key=lambda x: x[1])
removed = 0
prev_end = intervals[0][1]
for start, end in intervals[1:]:
if start < prev_end:
removed += 1 # Conflict! Drop the later-ending meeting
else:
prev_end = end
return removed4. Core Interview Patterns & Common Traps
Use when inserting a new interval into an already sorted list of non-overlapping intervals in O(N) time without re-sorting.
res = []
i, n = 0, len(intervals)
# 1. Add all intervals that end strictly before newInterval starts
while i < n and intervals[i][1] < newInterval[0]:
res.append(intervals[i]); i += 1
# 2. Merge all intervals that start before or at newInterval's end
while i < n and intervals[i][0] <= newInterval[1]:
newInterval[0] = min(newInterval[0], intervals[i][0])
newInterval[1] = max(newInterval[1], intervals[i][1])
i += 1
res.append(newInterval)
# 3. Append the remaining intervals
return res + intervals[i:]| Operation / Pattern | Time | Space | Notes |
|---|---|---|---|
| Sort + Merge / Filter Intervals | O(N log N) | O(N) | Sorting takes O(N log N); linear scan takes O(N) |
| Insert into Already-Sorted Intervals | O(N) | O(N) | 1) Add all ending before new, 2) Merge overlaps, 3) Add rest |
5. Practice On Your Own (Curated Submodule Problems)
| Status | Problem | Difficulty | Complexity | Hint? | Links & Notes |
|---|---|---|---|---|---|
Merge Intervals Sort by Start Time (Merge / Insert Intervals) | Medium | T: O(N log N) S: O(N) | |||
Insert Interval Sort by Start Time (Merge / Insert Intervals) | Medium | T: O(N) S: O(N) | |||
Non-overlapping Intervals Sort by End Time (Activity Selection) | Medium | T: O(N log N) S: O(1) |