CodeX
Published in

CodeX

You have 2 free member-only stories left this month.

Grokking the Coding Interview: Pattern Merge Interval

How learning coding patterns make interview preparation easy and efficient.

Image by rawpixel.com

Being a pro at coding patterns makes life easier because we can quickly spot similarities between new problems and ones we’ve tackled before. This makes finding solutions a breeze.

One super important coding pattern to know is the Merge Interval. On is one of the most frequently occurring patterns in Coding Interviews. Let’s dive in and learn when and how to use it.

Merge Interval pattern describes an efficient technique to deal with overlapping intervals. In a lot of problems involving intervals, we either need to find overlapping intervals or merge intervals if they overlap.

Given two intervals (‘a’ and ‘b’), there will be six different ways the two intervals can relate to each other:

Understanding the above six cases will help us in solving all intervals related problems.

Let’s jump onto a coding problem to understand the Merge Interval pattern.

For a detailed discussion of these patterns and related problems with solutions, take a look at Grokking the Coding Interview.

Merge Intervals (medium)

Problem Statement

Given a list of intervals, merge all the overlapping intervals to produce a list that has only mutually exclusive intervals.

Example 1:

Intervals: [[1,4], [2,5], [7,9]]
Output: [[1,5], [7,9]]
Explanation: Since the first two intervals [1,4] and [2,5] overlap, we
merged them into one [1,5].

Example 2:

Intervals: [[6,7], [2,4], [5,9]]
Output: [[2,4], [5,9]]
Explanation: Since the intervals [6,7] and [5,9] overlap, we merged
them into one [5,9].

Example 3:

Intervals: [[1,4], [2,6], [3,5]]
Output: [[1,6]]
Explanation: Since all the given intervals overlap, we merged them
into one.

Solution

Let’s take the example of two intervals (‘a’ and ‘b’) such that a.start <= b.start. There are four possible scenarios:

Our goal is to merge the intervals whenever they overlap. For the above-mentioned three overlapping scenarios (2, 3, and 4), this is how we will merge them:

The diagram above clearly shows a merging approach. Our algorithm will look like this:

  1. Sort the intervals on the start time to ensure a.start <= b.start.
  2. If ‘a’ overlaps ‘b’ (i.e. b.start <= a.end), we need to merge them into a new interval ‘c’ such that:
c.start = a.start
c.end = max(a.end, b.end)

3. We will keep repeating the above two steps to merge ‘c’ with the next interval if it overlaps with ‘c’.

Code

Here is what our algorithm will look like in Python (Jave solution right after it):

Python3

from __future__ import print_function


class Interval:
def __init__(self, start, end):
self.start = start
self.end = end

def print_interval(self):
print("[" + str(self.start) + ", " + str(self.end) + "]", end='')


def merge(intervals):
if len(intervals) < 2:
return intervals

# sort the intervals on the start time
intervals.sort(key=lambda x: x.start)

mergedIntervals = []
start = intervals[0].start
end = intervals[0].end
for i in range(1, len(intervals)):
interval = intervals[i]
if interval.start <= end: # overlapping intervals, adjust the 'end'
end = max(interval.end, end)
else: # non-overlapping interval, add the previous interval and reset
mergedIntervals.append(Interval(start, end))
start = interval.start
end = interval.end

# add the last interval
mergedIntervals.append(Interval(start, end))
return mergedIntervals


def main():
print("Merged intervals: ", end='')
for i in merge([Interval(1, 4), Interval(2, 5), Interval(7, 9)]):
i.print_interval()
print()

print("Merged intervals: ", end='')
for i in merge([Interval(6, 7), Interval(2, 4), Interval(5, 9)]):
i.print_interval()
print()

print("Merged intervals: ", end='')
for i in merge([Interval(1, 4), Interval(2, 6), Interval(3, 5)]):
i.print_interval()
print()


main()

Java

import java.util.*;

class Interval {
int start;
int end;

public Interval(int start, int end) {
this.start = start;
this.end = end;
}
};

class Solution {

public static List<Interval> merge(List<Interval> intervals) {
if (intervals.size() < 2)
return intervals;

// sort the intervals by start time
Collections.sort(intervals, (a, b) -> Integer.compare(a.start, b.start));

List<Interval> mergedIntervals = new LinkedList<Interval>();
Iterator<Interval> intervalItr = intervals.iterator();
Interval interval = intervalItr.next();
int start = interval.start;
int end = interval.end;

while (intervalItr.hasNext()) {
interval = intervalItr.next();
if (interval.start <= end) { // overlapping intervals, adjust the 'end'
end = Math.max(interval.end, end);
} else { // non-overlapping interval, add the previous interval and reset
mergedIntervals.add(new Interval(start, end));
start = interval.start;
end = interval.end;
}
}
// add the last interval
mergedIntervals.add(new Interval(start, end));

return mergedIntervals;
}

public static void main(String[] args) {
List<Interval> input = new ArrayList<Interval>();
input.add(new Interval(1, 4));
input.add(new Interval(2, 5));
input.add(new Interval(7, 9));
System.out.print("Merged intervals: ");
for (Interval interval : Solution.merge(input))
System.out.print("[" + interval.start + "," + interval.end + "] ");
System.out.println();

input = new ArrayList<Interval>();
input.add(new Interval(6, 7));
input.add(new Interval(2, 4));
input.add(new Interval(5, 9));
System.out.print("Merged intervals: ");
for (Interval interval : Solution.merge(input))
System.out.print("[" + interval.start + "," + interval.end + "] ");
System.out.println();

input = new ArrayList<Interval>();
input.add(new Interval(1, 4));
input.add(new Interval(2, 6));
input.add(new Interval(3, 5));
System.out.print("Merged intervals: ");
for (Interval interval : Solution.merge(input))
System.out.print("[" + interval.start + "," + interval.end + "] ");
System.out.println();
}
}

Time Complexity

The time complexity of the above algorithm is O(N * logN), where ’N’ is the total number of intervals. We are iterating the intervals only once which will take O(N), in the beginning though, since we need to sort the intervals, our algorithm will take O(N * logN).

Space Complexity

The space complexity of the above algorithm will be O(N) as we need to return a list containing all the merged intervals. We will also need O(N) space for sorting. For Java, depending on its version, Collections.sort() either uses Merge sort or Timsort, and both these algorithms need O(N) space. Overall, our algorithm has a space complexity of O(N).

Similar Problems

Problem 1: Given a set of intervals, find out if any two intervals overlap.

Example:

Intervals: [[1,4], [2,5], [7,9]]
Output: true
Explanation: Intervals [1,4] and [2,5] overlap

Solution: We can follow the same approach as discussed above to find if any two intervals overlap.

Where to go from here

Learn more about the Merge Interval pattern in Grokking the Coding Interview.

Here are a few good posts on coding and system design interviews:

Sign up for CrunchX

By CodeX

A weekly newsletter on what's going on around the tech and programming space Take a look.

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Medium sent you an email at to complete your subscription.

Everything connected with Tech & Code. Follow to join our 1M+ monthly readers

Share your ideas with millions of readers.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store