Meeting Room
Merging Overlapping Intervals: Meeting Room
The task of merging overlapping intervals is a frequent problem in computer science, often encountered in scheduling and timeline management scenarios.
In this article, we’ll explore how to merge intervals and return a concise, non-overlapping set that covers all the given ranges.
Problem Description
You are given an array of intervals where each interval is represented as intervals[i] = [start_i, end_i]
. Your task is to merge all overlapping intervals into a single interval whenever possible and return the resulting array.
Key Points:
Overlapping Definition: Two intervals overlap if their ranges have at least one common point.
- For example:
[1,2]
and[3,4]
are non-overlapping.[1,2]
and[2,3]
overlap, as they share the point2
.
- For example:
Goal: Minimize the total number of intervals by merging overlapping ones.
Explanation:
(0,30)
and(5,10)
will conflict(0,30)
and(15,20)
will conflict
Explanation:
- (0,8),(8,10) is not considered a conflict at 8
Approach to Solve the Problem
To solve this problem effectively, we can use the following approach:
Step 1: Sort the Intervals
- Sorting the intervals by their start time ensures that overlapping intervals appear consecutively in the list. This makes it easier to merge them.
Step 2: Merge Overlapping Intervals
- Use a result list to store merged intervals.
- Compare each interval with the last interval in the result list:
- If they overlap, merge them by updating the end of the last interval to the maximum end time.
- If they don’t overlap, add the current interval to the result list.
Algorithm
- Sort the intervals based on their start time.
- Initialize an empty list
merged
to store the result. - Iterate through the sorted intervals:
- If the current interval overlaps with the last merged interval, merge them.
- Otherwise, add the current interval to the result list.
There are mainly three approach to solve this problem –
- Brute Force
- Sweep Line Algorithm
- Greedy
1. Brute Force
- Time complexity: O(2^n)
- Space complexity: O(1)
""" Definition of Interval: class Interval(object): def __init__(self, start, end): self.start = start self.end = end """ class Solution: def canAttendMeetings(self, intervals: List[Interval]) -> bool: n = len(intervals) for i in range(n): A = intervals[i] for j in range(i + 1, n): B = intervals[j] if min(A.end, B.end) > max(A.start, B.start): return False return True
/** * Definition of Interval: * class Interval { * public: * int start, end; * Interval(int start, int end) { * this->start = start; * this->end = end; * } * } */ class Solution { public: bool canAttendMeetings(vector& intervals) { int n = intervals.size(); for (int i = 0; i < n; i++) { Interval& A =intervals[i]; for (int j = i + 1; j < n; j++) { Interval& B =intervals[j]; if (min(A.end, B.end) > max(A.start, B.start)) { return false; } } } return true; } };
/** * Definition of Interval: * public class Interval { * public int start, end; * public Interval(int start, int end) { * this.start = start; * this.end = end; * } * } */ public class Solution { public boolean canAttendMeetings(Listintervals) { int n = intervals.size(); for (int i = 0; i < n; i++) { Interval A = intervals.get(i); for (int j = i + 1; j < n; j++) { Interval B = intervals.get(j); if (Math.min(A.end, B.end) > Math.max(A.start, B.start)) { return false; } } } return true; } }
/** * Definition of Interval: * class Interval { * constructor(start, end) { * this.start = start; * this.end = end; * } * } */ class Solution { /** * @param {Interval[]} intervals * @returns {boolean} */ canAttendMeetings(intervals) { const n = intervals.length; for (let i = 0; i < n; i++) { const A = intervals[i]; for (let j = i + 1; j < n; j++) { const B = intervals[j]; if (Math.min(A.end, B.end) > Math.max(A.start, B.start)) { return false; } } } return true; } }
2. Sorting
Time & Space Complexity
- Time complexity: O(nlogn)
- Space complexity: O(1) or O(n) depending on the sorting algorithm.
Code
/** * Definition of Interval: * class Interval { * public: * int start, end; * Interval(int start, int end) { * this->start = start; * this->end = end; * } * } */ class Solution { public: bool canAttendMeetings(vector& intervals) { sort(intervals.begin(), intervals.end(), [](auto& x, auto& y) { return x.start < y.start; }); for (int i = 1; i < intervals.size(); ++i) { if (intervals[i].start < intervals[i - 1].end) { return false; } } return true; } };
/** * Definition of Interval: * public class Interval { * public int start, end; * public Interval(int start, int end) { * this.start = start; * this.end = end; * } * } */ public class Solution { public boolean canAttendMeetings(Listintervals) { Collections.sort(intervals, Comparator.comparingInt(i -> i.start)); for (int i = 1; i < intervals.size(); i++) { Interval i1 = intervals.get(i - 1); Interval i2 = intervals.get(i); if (i1.end > i2.start) { return false; } } return true; } }
""" Definition of Interval: class Interval(object): def __init__(self, start, end): self.start = start self.end = end """ class Solution: def canAttendMeetings(self, intervals: List[Interval]) -> bool: intervals.sort(key=lambda i: i.start) for i in range(1, len(intervals)): i1 = intervals[i - 1] i2 = intervals[i] if i1.end > i2.start: return False return True
/** * Definition of Interval: * class Interval { * constructor(start, end) { * this.start = start; * this.end = end; * } * } */ class Solution { /** * @param {Interval[]} intervals * @returns {boolean} */ canAttendMeetings(intervals) { intervals.sort((a, b) => a.start - b.start); for (let i = 1; i < intervals.length; i++) { if (intervals[i].start < intervals[i - 1].end) { return false; } } return true; } }