LeetCode Β· #56
Merge Intervals Solution
Given an array of intervals, merge all overlapping intervals and return the non-overlapping result.
01
Section One Β· Problem
Problem Statement
Given array of intervals where intervals[i] = [startα΅’, endα΅’], merge all overlapping intervals and return an array of non-overlapping intervals that cover all input ranges.
Example
Input: intervals = [[1,3],[2,6],[8,10],[15,18]]
Output: [[1,6],[8,10],[15,18]]
// [1,3] and [2,6] overlap β merged to [1,6]
Constraints
β’ 1 β€ intervals.length β€ 10β΄ β’ intervals[i].length == 2 β’ 0 β€ startα΅’ β€ endα΅’ β€ 10β΄
02
Section Two Β· Approach 1
Brute Force β O(nΒ²)
For each interval, compare against all others to find overlaps and merge. Repeat until no more merges possible.
Problem: O(nΒ²) comparisons per pass, possibly multiple passes. Sorting by start first means overlapping intervals are adjacent β one linear scan suffices after sorting.
Java β Sort + naive merge
import java.util.*;
class Solution {
public int[][] merge(int[][] intervals) {
Arrays.sort(intervals, (a,b) -> a[0] - b[0]);
LinkedList<int[]> res = new LinkedList<>();
for (int[] iv : intervals) {
if (res.isEmpty() || res.getLast()[1] < iv[0])
res.add(iv); // no overlap else
res.getLast()[1] = Math.max(res.getLast()[1], iv[1]); // merge
}
return res.toArray(new int[res.size()][]);
}
}
Python β Sort + merge
class Solution:
def merge(self, intervals: list[list[int]]) -> list[list[int]]:
intervals.sort()
res = [intervals[0]]
for s, e in intervals[1:]:
if s > res[-1][1]:
res.append([s, e])
else:
res[-1][1] = max(res[-1][1], e)
return res
| Metric | Value |
|---|---|
| Time | O(n log n) β dominated by sort |
| Space | O(n) β output array |
03
Section Three Β· Approach 2
Sort + Linear Merge β O(n log n)
Sort intervals by start time. Iterate: if the current interval overlaps the last merged one (start β€ last.end), extend the end. Otherwise, start a new merged interval.
π‘ Mental model: Imagine laying colored ribbons on a timeline. Sort them left to right by their start. Walk along: if the next ribbon's start is before the current ribbon's end, they overlap β stretch the current ribbon to cover both. If the next ribbon starts after the current one ends, place a new ribbon. The result is the fewest ribbons that cover all the same ground.
Algorithm
- Sort by
startascending. - Initialize result with first interval.
- For each subsequent interval: if
start β€ last.endβ merge (extend end). Else β append new interval. - Return result.
π― When to recognize this pattern: "Merge overlapping intervals." THE foundational interval problem. Sorting by start guarantees overlapping intervals are adjacent. Variants: LC 57 (Insert Interval), LC 435 (Non-overlapping β sort by end), LC 253 (Meeting Rooms II β heap for concurrent count).
Why sort by start? After sorting, if interval B's start > interval A's end, then ALL subsequent intervals also start after A (because they're sorted). So A is finalized β no future interval can overlap it. This monotonicity enables the single-pass merge.
04
Section Four Β· Trace
Visual Walkthrough
Trace for intervals = [[1,3],[2,6],[8,10],[15,18]].
Merge Intervals β Sort + Linear Scan
05
Section Five Β· Implementation
Code β Java & Python
Java β Sort + merge
import java.util.*;
class Solution {
public int[][] merge(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
List<int[]> res = new ArrayList<>();
for (int[] iv : intervals) {
if (res.isEmpty() || res.get(res.size()-1)[1] < iv[0])
res.add(iv);
else
res.get(res.size()-1)[1] = Math.max(res.get(res.size()-1)[1], iv[1]);
}
return res.toArray(new int[res.size()][]);
}
}
Python β Sort + merge
class Solution:
def merge(self, intervals: list[list[int]]) -> list[list[int]]:
intervals.sort()
res = [intervals[0]]
for s, e in intervals[1:]:
if s <= res[-1][1]:
res[-1][1] = max(res[-1][1], e)
else:
res.append([s, e])
return res
06
Section Six Β· Analysis
Complexity Analysis
| Approach | Time | Space | Trade-off |
|---|---|---|---|
| Brute force (pairwise) | O(nΒ²) | O(n) | Multi-pass merging |
| Sort + merge β optimal | O(n log n) | O(n) | Single pass after sort; can't beat O(n log n) without sorted input |
07
Section Seven Β· Edge Cases
Edge Cases & Pitfalls
| Case | Input | Why It Matters |
|---|---|---|
| Single interval | [[1,5]] | Return as-is. |
| All overlap | [[1,4],[2,5],[3,6]] | One merged interval [1,6]. |
| No overlap | [[1,2],[3,4],[5,6]] | All unchanged. |
| Contained interval | [[1,10],[2,3]] | [2,3] is inside [1,10]. Result: [1,10]. |
| Touching endpoints | [[1,4],[4,5]] | 4==4 β they overlap. Merge to [1,5]. |
β Common Mistake: Using strict less-than (
start < last.end) instead of less-than-or-equal (start β€ last.end). Intervals [1,4] and [4,5] touch at 4 and should be merged. The overlap condition is start β€ last.end, not start < last.end.