top of page

Merge Intervals

  • mosesg1123
  • 8 minutes ago
  • 3 min read

"Merge Intervals" is one of those classic algorithm problems that shows up frequently in technical interviews. It's a great test of your understanding of sorting, array manipulation, and edge case handling. In real-world scenarios, this type of logic appears in scheduling applications, calendar merging, or optimizing task execution windows.


Problem Statement

You are given an array of intervals where intervals[i] = [start_i, end_i]. Merge all overlapping intervals, and return an array of the non-overlapping intervals that cover all the intervals in the input.


1. Clarify Requirements Before Jumping Into Code

  • Are the intervals sorted? No.

  • Can an interval be fully contained within another? Yes.

  • Will the input have at least one interval? Yes.

  • What should we return if there are no overlapping intervals? Return the original intervals.


2. Identify the Category of the Question 

This problem resembles a greedy algorithm because we can make local decisions (combine two overlapping intervals) that lead to a globally correct result, which is the hallmark of a greedy strategy. There's no need to backtrack or reconsider previous choices, making the greedy approach both efficient and straightforward here.


3. Consider a Brute-Force Approach to Understand the Problem

The brute-force approach would be to compare every interval with every other interval. If they overlap, we merge accordingly. But since we are scanning the whole array for every element, we get a runtime of O(n^2), which is not great.


Time Complexity: O(n^2), which is not efficient for larger inputs.


4. Brainstorm More Solutions

Part of the reason our brute-force solution is so inefficient is because overlapping intervals can be found anywhere in our input array. Our O(n^2) runtime comes from the fact that we have to scan the whole array on every iteration.


If we knew for a fact that overlapping intervals could be found immediately next to each other, then we wouldn't have to scan the whole array for a match. In fact, we could solve the problem with just one pass through the array because all we would need to do is compare an element against it's immediate neighbors.


So, as an optimization, let's start by sorting our array. We can do that in O(n log n) time.


Then, we iterate through our array:

  • If the current interval overlaps with the previous one, merge them.

  • Otherwise, add the current interval to the result.


Time Complexity: O(n log n)


5. Discuss Trade-Offs Between Your Solutions

Approach

Time Complexity

Space Complexity

Pros

Cons

Brute-force

O(n^2)

O(n)

Simple to implement

Very inefficient for large n

Greedy after sorting

O(n log n)

O(n)

Efficient, clean, widely applicable

Slightly more complex logic


6. Write Pseudocode to Structure Your Thoughts

function mergeIntervals(intervals):
    if intervals is empty:
        return []

    sort intervals by start time
    merged = [intervals[0]]

    for interval in intervals[1:]:
        last = merged[-1]
        if interval[0] <= last[1]:
            last[1] = max(last[1], interval[1])
        else:
            merged.append(interval)

    return merged

7. Consider Edge Cases

  • Only one interval: should return that interval.

  • Completely overlapping intervals.

  • No overlaps at all.

  • Nested intervals (e.g., [1,10], [2,3]).


8. Write Full Code Syntax

import java.util.*;

public class MergeIntervals {
    public int[][] merge(int[][] intervals) {
        if (intervals.length == 0) return new int[0][0];

        // Sort intervals by start time
        Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));

        List<int[]> merged = new ArrayList<>();
        merged.add(intervals[0]);

        for (int i = 1; i < intervals.length; i++) {
            int[] last = merged.get(merged.size() - 1);
            int[] current = intervals[i];
            if (current[0] <= last[1]) {
                last[1] = Math.max(last[1], current[1]);
            } else {
                merged.add(current);
            }
        }

        return merged.toArray(new int[merged.size()][]);
    }
}

9. Test Your Code

assert merge([[1,3],[2,6],[8,10],[15,18]]) == [[1,6],[8,10],[15,18]]
assert merge([[1,4],[4,5]]) == [[1,5]]
assert merge([[1,4],[2,3]]) == [[1,4]]
assert merge([[1,4],[0,2],[3,5]]) == [[0,5]]
assert merge([[1,4]]) == [[1,4]]

10. Key Lessons to Remember for Future Questions

  • Sorting often simplifies interval-related problems.

  • Always consider edge cases like containment and exact overlaps.

  • A single-pass greedy approach after sorting is a powerful pattern for these kinds of problems.

  • Keep code clean and readable by separating concerns: sorting, iterating, and merging.


Good Luck and Happy Coding!

Recent Posts

See All
Jump Game II

Jump Game II is a classic follow-up to the original Jump Game problem. It’s not just about whether you can reach the end... now you have to do it in the fewest jumps possible! That small change turns

 
 
 
Jump Game

The "Jump Game" question is a popular one for interviews because it tests your ability to think greedily and work with dynamic movement through an array. It's a great warm-up for range-based greedy lo

 
 
 
Gas Station

The "Gas Station" problem is one of those deceptively simple problems that really tests your understanding of greedy strategies and circular arrays. It shows up frequently in interviews because it ble

 
 
 

Comments


Drop Me a Line, Let Me Know What You Think

Thanks for submitting!

© 2023 by Train of Thoughts. Proudly created with Wix.com

bottom of page