Problem
You are given a 2D integer array intervals
where intervals[i] = [lefti, righti]
represents the inclusive interval [lefti, righti]
.
You have to divide the intervals into one or more groups such that each interval is in exactly one group, and no two intervals that are in the same group intersect each other.
Return the minimum number of groups you need to make.
Two intervals intersect if there is at least one common number between them. For example, the intervals [1, 5]
and [5, 8]
intersect.
Examples
Example 1:
Input: intervals = [[5,10],[6,8],[1,5],[2,3],[1,10]]
Output: 3
Explanation: We can divide the intervals into the following groups:
- Group 1: [1, 5], [6, 8].
- Group 2: [2, 3], [5, 10].
- Group 3: [1, 10].
It can be proven that it is not possible to divide the intervals into fewer than 3 groups.
Example 2:
Input: intervals = [[1,3],[5,6],[8,10],[11,13]]
Output: 1
Explanation: None of the intervals overlap, so we can put all of them in one group.
Solution
Method 1 - Sorting
Here is the approach:
- Definition of Intersection: Two intervals
[lefti, righti]
and[leftj, rightj]
intersect ifleftj <= righti
andlefti <= rightj
. - Greedy Approach:
- Sort the intervals based on their start times.
- Use a min-heap to keep track of the end times of intervals in the current groups.
- Iterate through each interval and check if it can be placed in any of the existing groups (represented by the heap).
- Detailed Steps:
- Sort the intervals based on their start times.
- Initialize a min-heap to track the earliest ending interval in each group.
- Iterate through the sorted intervals:
- Use the heap to check and remove any group that can accommodate the current interval.
- Add the current interval’s end time to the heap (representing a new or extended group).
- The size of the heap at the end of the iteration gives the minimum number of groups required.
Code
Java
public class Solution {
public int minGroups(int[][] intervals) {
// Sort intervals by start time
Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
// Min-heap to track the end times of the intervals in current groups
PriorityQueue<Integer> heap = new PriorityQueue<>();
for (int[] interval : intervals) {
// If the smallest end time in the heap is less than the start of current interval,
// it means we can reuse this group
if (!heap.isEmpty() && heap.peek() < interval[0]) {
heap.poll(); // Remove that interval
}
// Add the end time of the current interval to heap
heap.offer(interval[1]);
}
// The size of the heap represents the minimum number of groups
return heap.size();
}
}
Python
class Solution:
def minGroups(self, intervals: List[List[int]]) -> int:
# Sort intervals by start time
intervals.sort(key=lambda x: x[0])
# Min-heap to track the end times of the intervals in current groups
heap = []
for interval in intervals:
# If the smallest end time in the heap is less than the start of current interval,
# it means we can reuse this group
if heap and heap[0] < interval[0]:
heapq.heappop(heap) # Remove that interval
# Add the end time of the current interval to heap
heapq.heappush(heap, interval[1])
# The size of the heap represents the minimum number of groups
return len(heap)
Complexity
- ⏰ Time complexity:
O(n log n)
wheren
is the number of intervals. The sorting step takesO(n log n)
time, and each heap operation (insert and extract) isO(log n)
, leading to a total complexity for heap operations asO(n log n)
. - 🧺 Space complexity:
O(n)
, for storing intervals in the heap.