Greedy Interval Scheduling solves the Interval Scheduling problem.
The Interval Scheduling problem asks for the maximum number of mutually non-overlapping intervals (jobs, events, tasks) that can be scheduled. A greedy strategy works surprisingly well here: always select the interval that finishes earliest. This choice maximizes the remaining time for subsequent intervals.
Here is the algorithm in more formal steps:
currentTime = -\infty
.[start, end]
in sorted order:
start \geq currentTime
:
currentTime = end
.This algorithm is greedy because it always chooses the locally optimal step—selecting the interval that ends the soonest—without reconsidering earlier decisions.
Interval | Start | End |
---|---|---|
A | 1 | 4 |
B | 3 | 5 |
C | 0 | 6 |
D | 5 | 7 |
E | 3 | 8 |
F | 5 | 9 |
G | 6 | 10 |
H | 8 | 11 |
I | 8 | 12 |
J | 2 | 13 |
K | 12 | 14 |
Sorted by finish time, the algorithm selects: A, D, H, K.
int intervalSchedule(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> Integer.compare(a[1], b[1]));
int count = 0, current = Integer.MIN_VALUE;
for (int[] interval : intervals) {
if (interval[0] >= current) {
count++;
current = interval[1];
}
}
return count;
}
int intervalSchedule(vector> &intervals) {
sort(intervals.begin(), intervals.end(), [](auto &a, auto &b) {
return a.second < b.second;
});
int count = 0, current = INT_MIN;
for (auto &interval : intervals) {
if (interval.first >= current) {
count++;
current = interval.second;
}
}
return count;
}
def interval_schedule(intervals):
intervals.sort(key=lambda x: x[1])
count = 0
current = float('-inf')
for start, end in intervals:
if start >= current:
count += 1
current = end
return count
Time Complexity: The sort step takes \(O(n \log n)\), and the single pass over the sorted intervals takes \(O(n)\). So the total time is \(O(n \log n)\).
Space Complexity: The algorithm uses \(O(1)\) extra space if sorting is done in place; otherwise, \(O(n)\) if the sort creates a new list.