56. Merge Intervals
On LeetCode ->Problem¶
Merge a list of closed intervals so that any overlapping or touching intervals become one interval, and return the merged list.
Example:
Key trick¶
Sort intervals by start, then scan once while keeping the last merged interval.
Trap¶
- Forgetting to sort first.
- Using
>instead of>=, which wrongly fails to merge touching intervals like[1,4]and[4,5]. - Appending the current interval too early instead of extending the previous merged one.
- Not handling intervals fully contained inside another, like
[1,10]and[2,3].
Why is it interesting?¶
It is a simple pattern that tests whether you can turn an apparently pairwise-overlap problem into sorting plus one linear pass, giving \(O(n \log n)\) instead of messy repeated comparisons.
Python solution¶
class Solution:
def merge(self, intervals: list[list[int]]) -> list[list[int]]:
# Sort by left endpoint so any possible overlap is next to each other.
intervals.sort(key=lambda interval: interval[0])
merged = []
for start, end in intervals:
# No overlap with previous merged interval: start a new one.
if not merged or merged[-1][1] < start:
merged.append([start, end])
else:
# Overlap or touch: extend the previous interval.
merged[-1][1] = max(merged[-1][1], end)
return merged
Comment on my solution¶
- Your solution is correct and interview-ready.
- The core idea is exactly the standard optimal approach: sort, then merge in one pass.
- Minor wording issue:
Brute forceis misleading here, since this is the optimal common solution, not brute force.
- Minor style improvement:
intervals.sort(...)avoids creating a second list if mutating input is acceptable.
- Your overlap condition and
maxupdate are both correct, including touching intervals and containment cases.
Complexity:
- Time: \(O(n \log n)\)
- Space:
- \(O(n)\) for the output
- plus \(O(n)\) extra in your version because
sorted(...)creates a new list
## Solution
# Works
class Solution:
def merge(self, intervals: list[list[int]]) -> list[list[int]]:
# [[1,3],[2,6],[8,10],[15,18]] -> [[1,6],[8,10],[15,18]]
# Brute force:
# - sort comparing the left bound
# - merge consecutive intervals a, b if a_right >= b_left
# - carefull because b can be include in a
sorted_intervals = sorted(intervals, key=lambda x: x[0])
merged = [sorted_intervals[0]]
for b in sorted_intervals[1:]:
a = merged[-1]
if a[1] >= b[0]:
merged[-1] = [a[0], max(a[1], b[1])]
else:
merged.append(b)
return merged
sorted([[2,6],[1,3],[15,18],[8,10]], key=lambda x: x[0]) # [[1, 3], [2, 6], [8, 10], [15, 18]]
Solution().merge([[2,6],[1,3],[15,18],[8,10]]) # [[1, 6], [8, 10], [15, 18]]
Solution().merge([[1,4],[4,5]]) # [[1, 5]]
Solution().merge([[4,7],[1,4]]) # [[1, 7]]