150NeetCode 150

131.Merge Intervals

MediumBlind 75Intervals · 2/6

Problem

Given an array intervals where intervals[i] = [start_i, end_i], merge all overlapping intervals and return an array of the non-overlapping intervals that cover exactly the same points.

Intervals that share an endpoint ([1,4] and [4,5]) overlap and must be merged. The input is not sorted; the output may be in any order.

Examples

Input:  intervals = [[1,3],[2,6],[8,10],[15,18]]
Output: [[1,6],[8,10],[15,18]]
Explanation: [1,3] and [2,6] overlap -> [1,6].
Input:  intervals = [[1,4],[4,5]]
Output: [[1,5]]
Explanation: They touch at 4, which counts as overlapping.
Input:  intervals = [[4,7],[1,4]]
Output: [[1,7]]
Explanation: Unsorted input — after ordering by start they touch at 4.

Constraints

  • 1 <= intervals.length <= 10^4
  • intervals[i].length == 2
  • 0 <= start_i <= end_i <= 10^4

💡 Key Insight

After sorting by start, any interval that overlaps the current merged block must come immediately after it — an interval that starts later than the block's end means no later interval (with an even larger start) can reach back into the block. So one sweep that either extends the last block's end or starts a new block is enough.

Brute Force (Repeated Pairwise Merge)

TimeO(n³)SpaceO(n)

Intuition

Keep merging any two overlapping intervals until no pair overlaps. Two intervals a, b overlap when a.start <= b.end && b.start <= a.end; their union is [min(starts), max(ends)].

Algorithm

  1. Copy intervals into a list.
  2. Repeat: scan all pairs (i, j); on the first overlapping pair, replace i with the union, remove j, and restart the scan.
  3. Stop when a full scan finds no overlapping pair.

Visualization

[[1,3],[2,6],[8,10],[15,18]]
pass 1: (1,3) & (2,6) overlap -> [[1,6],[8,10],[15,18]]
pass 2: no overlapping pair -> done

Code

java
import java.util.ArrayList;
import java.util.List;

class Solution {
    public int[][] merge(int[][] intervals) {
        List<int[]> list = new ArrayList<>();
        for (int[] in : intervals) {
            list.add(new int[] {in[0], in[1]});
        }
        boolean changed = true;
        while (changed) {
            changed = false;
            search:
            for (int i = 0; i < list.size(); i++) {
                for (int j = i + 1; j < list.size(); j++) {
                    int[] a = list.get(i), b = list.get(j);
                    if (a[0] <= b[1] && b[0] <= a[1]) { // overlap test
                        a[0] = Math.min(a[0], b[0]);
                        a[1] = Math.max(a[1], b[1]);
                        list.remove(j);
                        changed = true;
                        break search; // restart scan after a merge
                    }
                }
            }
        }
        return list.toArray(new int[0][]);
    }
}

Complexity

  • Time: O(n³) — up to n - 1 merges, each preceded by an O(n²) pair scan.
  • Space: O(n) — the working list.

Complexity Comparison

Approach Time Space
Repeated Pairwise Merge O(n³) O(n)
Overlap Graph + Components O(n²) O(n²)
Sort and Sweep O(n log n) O(n)

Common Pitfalls

  • Setting last[1] = cur[1] instead of max(last[1], cur[1]) — breaks on nested intervals like [1,10],[2,3].
  • Using < vs <= wrongly: [1,4],[4,5] must merge, so a new block starts only when last[1] < cur[0].
  • Forgetting to sort — the input order is arbitrary.
  • Comparator a[0] - b[0] is safe for these bounds but can overflow with large negatives; Integer.compare avoids that.