Greedy (Sort by End Time)
Intuition
This is the classic interval scheduling problem. The greedy strategy is to always keep the interval that ends earliest, because it leaves the most room for future intervals. We sort all intervals by their end time, then greedily select non-overlapping intervals. For each interval, if its start is greater than or equal to the end of the last selected interval, we keep it. Otherwise, we must remove it. The answer is the total number of intervals minus the count of intervals we kept.
Algorithm
- Sort the intervals by their end time in ascending order.
- Initialize a counter `kept` to 1 (we always keep the first interval) and set `prevEnd` to the end of the first interval.
- For each subsequent interval, check if its start is >= `prevEnd`.
- If yes, it does not overlap. Increment `kept` and update `prevEnd` to this interval's end.
- If no, it overlaps with the previously kept interval. Skip it (it will be removed).
- Return `intervals.length - kept`.
O(n log n)SpaceO(1)Code (C++ · Java · Python · Go)
class Solution {
public:
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b) {
return a[1] < b[1];
});
int kept = 1;
int prevEnd = intervals[0][1];
for (int i = 1; i < (int)intervals.size(); i++) {
if (intervals[i][0] >= prevEnd) {
kept++;
prevEnd = intervals[i][1];
}
}
return intervals.size() - kept;
}
};class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> a[1] - b[1]);
int kept = 1;
int prevEnd = intervals[0][1];
for (int i = 1; i < intervals.length; i++) {
if (intervals[i][0] >= prevEnd) {
kept++;
prevEnd = intervals[i][1];
}
}
return intervals.length - kept;
}
}def eraseOverlapIntervals(intervals: List[List[int]]) -> int:
intervals.sort(key=lambda x: x[1])
kept = 1
prev_end = intervals[0][1]
for i in range(1, len(intervals)):
if intervals[i][0] >= prev_end:
kept += 1
prev_end = intervals[i][1]
return len(intervals) - keptimport "sort"
func eraseOverlapIntervals(intervals [][]int) int {
sort.Slice(intervals, func(i, j int) bool {
return intervals[i][1] < intervals[j][1]
})
kept := 1
prevEnd := intervals[0][1]
for i := 1; i < len(intervals); i++ {
if intervals[i][0] >= prevEnd {
kept++
prevEnd = intervals[i][1]
}
}
return len(intervals) - kept
}