Number line sorted by start · green: kept · dashed: removed · the line marks prevEnd
public int eraseOverlapIntervals(int[][] intervals) { Arrays.sort(intervals, (a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]); int res = 0; int prevEnd = intervals[0][1]; for (int i = 1; i < intervals.length; i++) { int start = intervals[i][0]; int end = intervals[i][1]; if (start >= prevEnd) { // no overlap prevEnd = end; } else { // overlap: drop the one that ends later res++; prevEnd = Math.min(end, prevEnd); } } return res;}
- [start, end]
- —
- prevEnd
- —
- res
- 0
Why it works
- Brute force tries every subset of intervals to keep and checks it for overlaps: O(2ⁿ · n). Removing the fewest is the same as keeping the most.
- Greedy: when two intervals clash, keep the one that ends first. It leaves the most room for everything to its right, so no optimal answer is ever hurt by that choice.
prevEndis the end of the last interval you kept. - Cost: the sort is O(n log n); the sweep is one comparison per interval, O(n), with O(1) extra space.
- Pitfall: on overlap, do not blindly keep the earlier interval.
prevEnd = Math.min(end, prevEnd)swaps in the new one when it ends sooner, like[2,4]replacing[1,20]. And use≥: touching intervals are fine. - Related: this is the activity-selection problem. Minimum Number of Arrows to Burst Balloons (452) is the same sweep with closed ends.