Find the bug · Medium

Fix Merge Intervals

Medium Find the bug Most askedSeen at Meta, Google, Bloomberg

merge(intervals) merges all overlapping intervals and returns them sorted by start. Intervals that only touch ([1, 2] and [2, 3]) also merge.

The code sorts correctly and handles the common case, but loses data for some inputs. Find the bug and fix it.

Example 1

Input: intervals = [[1, 3], [2, 6], [8, 10], [15, 18]]
Output: [[1, 6], [8, 10], [15, 18]]

Example 2

Input: intervals = [[1, 4], [2, 3]]
Output: [[1, 4]]
Explanation: The buggy version returns [[1, 3]].

The buggy code

function merge(intervals) {
  intervals.sort((a, b) => a[0] - b[0]);
  const out = [];
  for (const cur of intervals) {
    const last = out[out.length - 1];
    if (last && cur[0] <= last[1]) last[1] = cur[1];
    else out.push([...cur]);
  }
  return out;
}

Hints

Hint 1

What happens when the current interval lies completely inside the previous one?

Find and fix the bug

Loading the editor… (JavaScript is required to run code in your browser.)

Solution and explanation

Show the bug and the fix

Time O(n log n) · Space O(n)

The bug: when the current interval overlaps the last merged one, the code sets the end to cur[1]. If the current interval is contained in the previous one ([2, 3] inside [1, 4]), that shrinks the merged interval.

The fix: extend to the larger end: last[1] = max(last[1], cur[1]).

Fixed version

function merge(intervals) {
  intervals.sort((a, b) => a[0] - b[0]);
  const out = [];
  for (const cur of intervals) {
    const last = out[out.length - 1];
    if (last && cur[0] <= last[1]) last[1] = Math.max(last[1], cur[1]);
    else out.push([...cur]);
  }
  return out;
}

Common mistakes

  • Using < instead of <= for touching intervals.
  • Sorting by end instead of start.