Given a collection of intervals, merge all overlapping intervals.
For example:
Given \$[1,3],[2,6],[8,10],[15,18]\$,
return \$[1,6],[8,10],[15,18]\$.
My introduction of algorithm:
I worked on the algorithm several times before, and then also studied a few of "merge intervals" questions on this site, found a sibling question - Finding the total time elapsed in the union of time intervals. The two problems are very similar, my working solution for Leetcode \$56\$ is also \$O(nlogn)\$ time by first sorting the input interval start time, then do a linear scan of the sorted array.
I spent more than one hour to practice again and passed all test cases through leetcode online judge, but I tried three times. First time I forgot to add edge case, after the for
loop, Leetcode online judge showed me that the test case with one interval only failed, and then, I did not use sorted intervals in the code and then failed test cases with two intervals \$[1,4]\$,\$[0,4]\$ by returning \$[1,4]\$. Through practice, I added those two test cases in the code as well to remind me the importance of those two bases cases.
Also, I took more than five minutes to look up C# Comparator and then decided to use LINQ to sort the intervals, with a quick study of a Stack Overflow post. I'm still trying to figure out quickest way to sort in a C# implementation.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MergeIntervals
{
class Program
{
/**
* Definition for an interval.
*/
public class Interval {
public int start;
public int end;
public Interval() { start = 0; end = 0; }
public Interval(int s, int e) { start = s; end = e; }
}
static void Main(string[] args)
{
RunSampleTestcase1();
RunSampleTestcase2();
}
/*
* Test case:
* help to test intervals should be sorted first before merging.
* [1,4], [0,4] should not be [1,4]
*/
public static void RunSampleTestcase1()
{
IList<Interval> intervals = new List<Interval>();
intervals.Add(new Interval(1, 4));
intervals.Add(new Interval(0, 4));
IList<Interval> nonoverlapped = Merge(intervals);
Debug.Assert(nonoverlapped[0].start == 0 && nonoverlapped[0].end == 4);
}
/*
* Test case:
* help to test that edge case is handled properly .
* [1,4] should be [1,4], not []
* In other words, there is one interval in the input, the result should be itself.
* For loop
*/
public static void RunSampleTestcase2()
{
IList<Interval> intervals = new List<Interval>();
intervals.Add(new Interval(1, 4));
IList<Interval> nonoverlapped = Merge(intervals);
Debug.Assert(nonoverlapped.Count == 1);
}
/*
* Merge all overlapping intervals
* Output: all intervals are non-overlapped.
*
* Use LINQ to sort the intervals -
* http://stackoverflow.com/questions/15486/sorting-an-ilist-in-c-sharp
*/
public static IList<Interval> Merge(IList<Interval> intervals)
{
IList<Interval> nonOverlapped = new List<Interval>();
if(intervals == null || intervals.Count == 0)
{
return nonOverlapped;
}
IEnumerable<Interval> sortedEnumerable = intervals.OrderBy(f => f.start);
IList<Interval> sortedIntervals = sortedEnumerable.ToList();
Interval previous = sortedIntervals[0];
for (int i = 1; i < sortedIntervals.Count; i++)
{
Interval current = sortedIntervals[i];
/* Two intervals are not overlapped */
if(previous.end < current.start)
{
nonOverlapped.Add(previous);
previous = current;
continue;
}
/* merge two overlapped intervals, previous interval's start is
smaller than current's start */
previous = new Interval(previous.start, Math.Max(previous.end, current.end));
}
// edge case
nonOverlapped.Add(previous);
return nonOverlapped;
}
}
}