🧠
Sorting + Single Pass Coverage Check
💡 Sorting intervals by start ascending and end descending helps us identify coverage in one pass, improving efficiency drastically.
Intuition
Sort intervals so that if one interval covers another, it appears before it. Then track the maximum end seen so far to detect coverage.
Algorithm
- Sort intervals by start ascending, and if tie, by end descending.
- Initialize max_end to 0 and count to 0.
- Iterate through intervals; if current interval's end is less or equal to max_end, it is covered.
- Otherwise, update max_end and increment count.
- Return count.
💡 Sorting ensures covered intervals come after their covering intervals, so a single max_end variable suffices to detect coverage.
from typing import List
def remove_covered_intervals(intervals: List[List[int]]) -> int:
intervals.sort(key=lambda x: (x[0], -x[1]))
count = 0
max_end = 0
for _, end in intervals:
if end > max_end:
count += 1
max_end = end
return count
# Driver code
if __name__ == '__main__':
intervals = [[1,4],[3,6],[2,8]]
print(remove_covered_intervals(intervals)) # Output: 2
Line Notes
intervals.sort(key=lambda x: (x[0], -x[1]))Sort by start ascending, end descending to ensure coverage order
count = 0Initialize count of non-covered intervals
if end > max_endIf current interval extends beyond max_end, it is not covered
max_end = endUpdate max_end to current interval's end
import java.util.*;
public class RemoveCoveredIntervals {
public static int removeCoveredIntervals(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> a[0] != b[0] ? a[0] - b[0] : b[1] - a[1]);
int count = 0, maxEnd = 0;
for (int[] interval : intervals) {
if (interval[1] > maxEnd) {
count++;
maxEnd = interval[1];
}
}
return count;
}
public static void main(String[] args) {
int[][] intervals = {{1,4},{3,6},{2,8}};
System.out.println(removeCoveredIntervals(intervals)); // Output: 2
}
}
Line Notes
Arrays.sort(intervals, (a, b) -> a[0] != b[0] ? a[0] - b[0] : b[1] - a[1]);Sort intervals by start ascending, end descending
int count = 0, maxEnd = 0;Initialize count and maxEnd
if (interval[1] > maxEnd)Check if interval is not covered
maxEnd = interval[1];Update maxEnd to current interval's end
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int removeCoveredIntervals(vector<vector<int>>& intervals) {
sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b) {
if (a[0] != b[0]) return a[0] < b[0];
return a[1] > b[1];
});
int count = 0, maxEnd = 0;
for (auto& interval : intervals) {
if (interval[1] > maxEnd) {
count++;
maxEnd = interval[1];
}
}
return count;
}
int main() {
vector<vector<int>> intervals = {{1,4},{3,6},{2,8}};
cout << removeCoveredIntervals(intervals) << endl; // Output: 2
return 0;
}
Line Notes
sort(intervals.begin(), intervals.end(), ...Sort intervals by start ascending, end descending
int count = 0, maxEnd = 0;Initialize count and maxEnd
if (interval[1] > maxEnd)Check if current interval is not covered
maxEnd = interval[1];Update maxEnd to current interval's end
function removeCoveredIntervals(intervals) {
intervals.sort((a, b) => a[0] !== b[0] ? a[0] - b[0] : b[1] - a[1]);
let count = 0, maxEnd = 0;
for (const [, end] of intervals) {
if (end > maxEnd) {
count++;
maxEnd = end;
}
}
return count;
}
// Driver code
const intervals = [[1,4],[3,6],[2,8]];
console.log(removeCoveredIntervals(intervals)); // Output: 2
Line Notes
intervals.sort((a, b) => a[0] !== b[0] ? a[0] - b[0] : b[1] - a[1]);Sort intervals by start ascending, end descending
let count = 0, maxEnd = 0;Initialize count and maxEnd
if (end > maxEnd)Check if current interval is not covered
maxEnd = end;Update maxEnd to current interval's end
TimeO(n log n)
SpaceO(log n) or O(n) depending on sorting implementation
Sorting takes O(n log n), single pass is O(n). Space depends on sorting algorithm.
💡 For n=100000, sorting is efficient enough to run quickly in practice.
Interview Verdict: Accepted
This approach is efficient and accepted for large inputs, making it the preferred solution in interviews.