Level Up Your Coding Skills & Crack Interviews — Save up to 50% or more on Educative.io Today! Claim Discount

Arrow
Table of contents

56. Merge Intervals

The Merge Intervals problem is a classic introduction to the Intervals pattern. It is a favorite in interviews because it tests whether you can turn many possible overlap comparisons into a single, ordered pass. While repeatedly merging pairs may seem straightforward, this problem proves why sorting first is essential for merging ranges efficiently and correctly.

Problem statement

Given a list of intervals, where each interval is [start, end]. Our task is to merge every pair of overlapping intervals and return a new list containing only non-overlapping intervals, while still covering the full range represented by the original input.

Constraints:

  • 1 <= digits.length <= 100
  • 0 <= digits[i] <= 9
  • digits does not contain any leading 0‘s.

Examples

InputOutputExplanation
[[2, 4], [1, 5], [7, 9]][[1, 5], [7, 9]]After sorting, [1, 5] overlaps with [2, 4], so they merge into [1, 5]. The remaining interval: [7, 9] doesn’t overlap with that merged range.
[[1, 2], [2, 3], [3, 4]][[1, 4]]Even though one ends exactly where the next starts, they are considered overlapping, so [1, 2] merges with [2, 3], and the result merges again with [3, 4] to form [1, 4].
[[4, 7], [1, 4]][[1, 7]]Sorting gives [[1, 3],[2, 4],[5, 6],[7, 8]]. The first two overlap and merge into [1, 4]. The remaining intervals do not overlap with it or each other.

Naive approach

A naive approach is to use a nested loop to compare every pair of intervals: the outer loop picks an interval i, and the inner loop checks it against every later interval j where j > i. For each pair (i, j), you check whether they overlap. For intervals [a, b] and [c, d], an overlap exists if a <= d and c <= b. If you find an overlapping pair, merge them into a single interval, replace it with the original interval in the list, and then restart the scan from the beginning, as the newly merged interval may now overlap with intervals you have already processed. In the worst case, you end up doing many repeated passes over the same ranges, which becomes too slow when there are up to 104 intervals.

Optimal solution using Intervals

Overlaps become much easier to handle once we sort the intervals by start time. Once the intervals are in sorted order, each new interval presents only two possibilities: either it merges into the current range, or it starts a new one. For each subsequent interval, we compare it with the last merged range.

  •  If the next interval starts after the current interval ends, there’s no overlap, so you append the current interval and process the next interval.
  • Otherwise, the next interval starts before or at the current end, which means they overlap, so you merge them by extending the current end to max(current_end, next_end)

Repeat this process until all intervals have been processed.

Why do touching endpoints still merge? 

As the problem treats intervals like [1, 4] and [4, 5] as overlapping, so our overlap rule must be next_start <= current_end (not strictly < ). Using <= ensures that even intervals that share only an endpoint merge into a single continuous range, allowing the left-to-right traversal to work cleanly without additional conditions.

Algorithmic steps

This algorithm is implemented as follows:

  1. Sort intervals by their start time start.
  2. Create an empty list merged.
  3. iterate through intervals in sorted order.
    1. If merged is empty or the current interval does not overlap with the last merged one,
      1. Append it.
    2. Otherwise,
      1. Merge by updating the last interval’s end to max(last_end, current_end).
  4. In the end, return merged.

To better understand the solution, let’s walk through the algorithm using the illustration below:

1 / 7

Python implementation 

The code below implements the algorithm described above.

Code for the merge intervals problem

Time complexity

The time complexity of the solution is O(n log n) because we sort the nnn intervals first. After sorting, we perform a single pass through the list to merge, which is why sorting dominates.

Space complexity

The space complexity of this solution is O(n) because, in the worst case, the output list may contain all intervals if none overlap. Sorting may also use additional space depending on the language/runtime, but the dominant explicit extra space is the merged output.


Common pitfalls to avoid

  • Forgetting to sort first: Without sorting, you can miss merges because overlapping intervals might not be adjacent in the input.
  • Using the wrong overlap condition: If you check start >= last_end instead of start > last_end, you’ll incorrectly split intervals.
  • Not extending the end properly: When overlapping, you must set end = max(current_end, next_end), not just overwrite it.
  • Mutating references incorrectly: Be careful if you store references to original sublists; it’s usually safer to build merged intervals explicitly as shown.

Frequently Asked Questions

Why can’t we just merge intervals in the given order?

Because the input order is arbitrary. Two intervals that overlap might be far apart, so merging in-place without ordering can miss merges or require repeated rescans.

Why do we merge when endpoints touch (like [1,4] and [4,5])?

The problem explicitly treats them as overlapping, so the combined coverage should be continuous: [1,5].

Is there a faster-than-O(n log n) solution?

In general, no, because without extra assumptions, sorting is needed to reliably detect all overlaps.

Does the approach work with duplicate intervals or identical starts?

Yes. Sorting groups them together, and the merge step naturally collapses duplicates into one interval.

Share with others:

Leave a Reply

Your email address will not be published. Required fields are marked *