Given `N` intervals S = {E_{1},E_{2},…..E_{n}} with each E_{i} has start time `s _{i}` and end time

`e`. Some of these intervals are overlapping. The problem statement is to merge these overlapping intervals.

_{i}E

_{i}and E_{j}overlap whenstart timeof E_{j}i.esis less than_{j}end timeof E_{i}i.ee._{i}

For example:

Input:[(1,3),(2,4),(5,8), (6,9)]Output:[(1, 4),(5,9)]Explantion:Interval (1,3) and (2,4) and interval (5,8) and (6,9) overlap.

## Merge overlapping intervals solution

As we always do, first try to come up with brute force solution, given enough time and space and money, how would you solve this?

The natural course is to take `i ^{th}` interval and compare start time of all

`jth`intervals with end time of

`i`, if the start time of

^{th}`jth`interval is less than the end time of

`i`event, then you can merge intervals. What should be end time for merged interval then? It should be a maximum of end times of two merged intervals.

^{th}What will be the time complexity of this approach? We are not using any additional space, however, the worst-case time complexity is `O(n ^{2})`. Can we do better?

What are two times we are comparing in brute force solution? It’s the start time of one interval with the end time of another. If we arrange input in a specific order, can we reduce processing some entries?

If we sort all intervals based on their start time, `s _{i}` <

`s`<

_{i+1}`s`. Also, interval is always forward looking,

_{i+2}`e`>

_{i}`s`,

_{i}`e`>

_{i+1}`s`and so on.

_{i+1}If `s _{i}` is greater

`e`, then

_{i-1}`s`will be greater than

_{i+1}`e`, so no need to compare

_{i-1}`s`with

_{i+1}`e`, that is no need to go beyond immediate previous interval for any interval E

_{i-1}_{i}.

If `s _{i}` is less than

`e`, update

_{i-1}`e`with maximum of

_{i-1}`e`and

_{i-1}`e`and move to E

_{i}_{i+1}.

Notice that we need last interval E_{i-1} to decide if to merge new interval into previous one or keep it as standalone. A stack is the best data structure to use. The algorithm will look like:

- Consider interval E
_{i}. - If stack is empty, push E
_{i}to stack. - If stack is not empty, then pop interval at top of stack call it E
_{i-1}. - Compare
`s`, start time of E_{i}_{i}with`e`, end time of E_{i-1}_{i-1}. - If
`s`less than_{i}`e`, update_{i-1}`e`as max(_{i-1}`e`,_{i-1}`e`), as in maximum of end times of two intervals and push back E_{i}_{i-1}on to stack. - Else push E
_{i}on to stack. - Continue till all events are considered.
- At the end of processing, stack will contain all merged interval.

Let’s take an example and see how this algorithm works. We have following intervals and we have to merge overlapping intervals.

Find the maximum of end times of two intervals and update the previous interval with that end time and push it back on to stack.

At this point, when there is no more interval remaining, the stack contains all merged overlapping intervals.

### Merge intervals Java implementation

package com.company; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Stack; /** * Created by sangar on 8.4.18. */ public class OverlappingIntervals { public static ArrayList<Interval> mergeOverlappingIntervals(ArrayList<Interval> intervals){ ArrayList<Interval> mergedIntervals = new ArrayList<>(); Stack<Interval> s = new Stack(); //Sort the ArrayList of interval based on start time. Collections.sort(intervals, Comparator.comparing(p -> p.getStartTime())); for(Interval currentInterval : intervals){ if(s.empty())s.push(currentInterval); else { Interval previousInterval = s.pop(); if(previousInterval.getEndTime() > currentInterval.getStartTime()){ /* If current interval's start time is less than end time of previous interval, find max of end times of two intervals and push new interval on to stack. */ int endTime = Integer.max(previousInterval.getEndTime(), currentInterval.getEndTime()); /* Notice that we have created new interval and did not update the old one This concept is called as immutability of class */ s.push(new Interval(previousInterval.getStartTime(), endTime)); } else{ s.push(previousInterval); s.push(currentInterval); } } } while(!s.empty()){ mergedIntervals.add(s.pop()); } return mergedIntervals; } public static void main(String[] args) { ArrayList<Interval> intervals = new ArrayList<>(); intervals.add(new Interval(1,3)); intervals.add(new Interval(2,4)); intervals.add(new Interval(5,8)); intervals.add(new Interval(6,9)); ArrayList<Interval> mergedIntervals = mergeOverlappingIntervals(intervals); for (Interval interval : mergedIntervals){ System.out.print("(" + interval.getStartTime() +"," + interval.getEndTime() + ")"); } } }

**will be**

__merge overlapping intervals__`O(nlogn)`due to sorting with

`O(n)`extra space for stack and then copying into the list to return also takes

`O(n)`space.

There is another way to implement the same function without using the stack, here we use the fact that ArrayList in Java is implemented using the array as the base and getting an element at a particular index should be `O(1)` operation. The code looks more or less the same, however, there is no traversal of the stack at the end to create the list to return.

**find overlapping intervals**

public List<Interval> mergeOptimized(List<Interval> intervals) { if(intervals.size() == 0) return intervals; Collections.sort(intervals, (Interval a, Interval b) -> a.getStartTime() - b.getStartTime()); List<Interval> mergedIntervals = new ArrayList<Interval>(); for(Interval interval : intervals){ /*If the merged list is empty add the interval to it or check if the last interval in merged list overlaps /*Remember the get function on ArrayList is O(1) operation because Arraylists in Java are backed by arrays */ if(mergedIntervals.isEmpty() || mergedIntervals.get( mergedIntervals.size()-1).getEndTime() < interval.getStartTime() ){ mergedIntervals.add(interval); } else { int lastEndTime = Math.max( mergedIntervals.get(mergedIntervals.size()-1) .getEndTime(), interval.getEndTime() ); mergedIntervals.get(mergedIntervals.size()-1) .setEndTime(lastEndTime); } } return mergedIntervals; }

You can use the above snippet of code to submit for this leetcode problem and it should be accepted.

Please share if there is something missing or wrong. Also, please reach out to us at [email protected] if you want to contribute to the website and help others to learn by sharing your knowledge. If you are preparing for an interview and need some coaching to prepare for it, please sign up for the free session with us.