Problem Statement in English

You’re 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.


Approach

There are 2 solutions here, both with the same time complexity ($O(n \log n)$). One uses extra space and the other uses constant space.

I personally find the constant space solution more intuitive and easier to understand, so we’ll start from there.

Constant Space

The idea is to sort the intervals by their start time. Then, we can iterate through the sorted intervals, while maintaining a buffer interval that tells us the current merged interval, and merge them if they overlap.

The way we merge them is by checking if the end of the buffer interval is greater than or equal to the start of the current interval. If they overlap, we update the end of the buffer interval to be the maximum of the two ends. If they don’t overlap, we add the buffer interval to our result and update the buffer to be the current interval.

Remember to add the last buffer interval to the result after the loop.

Extra Space

This solution uses a dictionary to keep track of the start and end points of the intervals.

We increment the count at the start point and decrement it at the end point.

Then, we iterate through the sorted keys of the dictionary, maintaining a count of overlapping intervals.

When the count is 0, we mark the start of a new merged interval, and when it goes back to 0, we mark the end of that merged interval — using the start, and current location to create the merged interval.

And we’re done!


Solution in Python

  • Extra Space ($O(n)$ space)

class Solution:
    def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        ans = []
        db = defaultdict(int)

        for start, end in intervals:
            db[start]+=1
            db[end]-=1

        start = 0
        count = 0
        for location in sorted(db):
            if count == 0:
                start = location
            
            count+=db[location]

            if count == 0:
                ans.append((start, location))
            
        return ans
        
  • Constant Space ($O(1)$ space)

class Solution:
    def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        res = []
        intervals.sort()
        buffer = [intervals[0][0], intervals[0][1]]

        for start, stop in intervals:
            if buffer[1] < start:
                res.append(buffer.copy())
                buffer[0], buffer[1] = start, stop
            elif buffer[1] < stop:
                buffer[1] = stop
            
        res.append(buffer)

        return res

Mistakes I Made


And we are done.