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

🏷️

Difficulty

Medium

πŸ”—

LeetCode

Problem #56

πŸ—οΈ

Pattern

Intervals β€” sort + merge

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
MetricValue
TimeO(n log n) β€” dominated by sort
SpaceO(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 start ascending.
  • 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
Already sorted by start. Compare each interval to the last merged one. [1,3]: result = [[1,3]] [2,6]: 2 ≀ 3 (overlap) β†’ extend end to max(3,6)=6. result = [[1,6]] [8,10]: 8 > 6 (no overlap) β†’ append. result = [[1,6],[8,10]] [15,18]: 15 > 10 β†’ append. result = [[1,6],[8,10],[15,18]] return [[1,6],[8,10],[15,18]] βœ“
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

ApproachTimeSpaceTrade-off
Brute force (pairwise)O(nΒ²)O(n)Multi-pass merging
Sort + merge ← optimalO(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

CaseInputWhy 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.

← Back to Interval problems