Merge Intervals
Merge overlapping intervals — sort by start, linear scan, and the calendar/UI variants interviewers stack on top.
- dsa
- intervals
- sorting
- interview
- Meta
- Amazon
- Microsoft
- Uber
The problem
Given an array of intervals where intervals[i] = [startᵢ, endᵢ], merge all overlapping intervals and return an array of the non-overlapping intervals that cover the input.
Input: [[1,3],[2,6],[8,10],[15,18]]
Output: [[1,6],[8,10],[15,18]]
Input: [[1,4],[4,5]]
Output: [[1,5]] // touching ends usually count as overlap — confirm
Input: [[1,4],[0,4]]
Output: [[0,4]]
Clarify with the interviewer: is [1,4] and [4,5] overlapping? Classic LC says yes (inclusive ends).
Frontend cousins: merge selection ranges in an editor, combine booking slots, coalesce toast time windows, CSS animation segment merge.
Brute force
For each interval, scan all others and merge when they overlap, restarting until stable. Correct-ish, O(n²) or worse, painful bookkeeping. Mention only to discard.
Optimal: sort by start, linear merge
- Sort intervals by start ascending.
- Seed
mergedwith the first interval (copy). - For each next interval:
- If
start ≤ lastEnd→ overlap →lastEnd = max(lastEnd, end) - Else push a new interval
- If
function merge(intervals: number[][]): number[][] {
if (intervals.length === 0) return [];
intervals.sort((a, b) => a[0] - b[0]);
const merged: number[][] = [[intervals[0][0], intervals[0][1]]];
for (let i = 1; i < intervals.length; i++) {
const [start, end] = intervals[i];
const last = merged[merged.length - 1];
if (start <= last[1]) {
last[1] = Math.max(last[1], end);
} else {
merged.push([start, end]);
}
}
return merged;
}
| Time | O(n log n) sort dominates |
| Space | O(n) for output (or O(log n) sort stack depending on engine) |
Walk [[1,3],[2,6],[8,10],[15,18]]
| next | merged |
|---|---|
| seed | [[1,3]] |
[2,6] |
[[1,6]] (2 ≤ 3) |
[8,10] |
[[1,6],[8,10]] |
[15,18] |
[[1,6],[8,10],[15,18]] |
Overlap test (commit it)
Two closed intervals [a,b] and [c,d] with a ≤ c overlap iff c ≤ b.
Merged span: [a, max(b,d)].
If ends are half-open [start, end), touching endpoints may not merge — product-dependent.
Edge cases
- Empty input →
[] - Single interval → itself
- Fully nested:
[1,10]then[2,3]→ end stays 10 - Identical intervals → one
- Unsorted input — must sort; never assume order
- Negative times / zero-length
[5,5]— still valid intervals
Common bugs
- Sorting by end instead of start (breaks linear scan invariant)
- Using
<instead of≤when inclusive merge is required - Mutating input intervals when interviewer forbids it (clone first)
- Forgetting
Math.maxon ends when new interval sticks out past the old end
Related problems (same family)
| Problem | Twist |
|---|---|
| Insert Interval | Merge one new into sorted list |
| Non-overlapping Intervals | Min removals → sort by end |
| Meeting Rooms | Any overlap? |
| Meeting Rooms II | Min rooms → sweep / heap |
Interview delivery
- Clarify inclusive ends and empty input.
- Sort by start → scan.
- Code; dry-run nested + disjoint cases.
- O(n log n) / O(n).
- Name Insert Interval as a follow-up.