Non Overlapping Intervals Minimum Removal in DSA C++ - Time & Space Complexity
We want to find how fast we can decide the minimum number of intervals to remove so none overlap.
How does the time needed grow as the number of intervals grows?
Analyze the time complexity of the following code snippet.
#include <vector>
#include <algorithm>
int eraseOverlapIntervals(std::vector<std::pair<int,int>>& intervals) {
if (intervals.empty()) return 0;
std::sort(intervals.begin(), intervals.end(), [](auto &a, auto &b) { return a.second < b.second; });
int count = 0, end = intervals[0].second;
for (int i = 1; i < intervals.size(); ++i) {
if (intervals[i].first < end) {
++count;
} else {
end = intervals[i].second;
}
}
return count;
}
This code sorts intervals by their end time, then counts how many overlap to remove the minimum.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Sorting the intervals by their end time.
- How many times: Sorting takes about n log n steps for n intervals.
- Secondary operation: One loop through all intervals to count overlaps.
- How many times: This loop runs n-1 times, once per interval after the first.
Sorting grows faster than the loop, so it dominates the time.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 * log 10 = 33 steps |
| 100 | About 100 * log 100 = 664 steps |
| 1000 | About 1000 * log 1000 = 9966 steps |
Pattern observation: As n grows, sorting steps grow a bit faster than just n, roughly n times log n.
Time Complexity: O(n log n)
This means the time needed grows a bit faster than the number of intervals, mainly due to sorting.
[X] Wrong: "The loop checking overlaps is the slowest part, so complexity is O(n)."
[OK] Correct: Sorting the intervals takes more time than the loop, so it controls the overall speed.
Understanding how sorting affects time helps you explain your solution clearly and shows you know what part costs the most time.
"What if the intervals were already sorted by end time? How would the time complexity change?"
Practice
Non Overlapping Intervals Minimum Removal problem?Solution
Step 1: Understand the problem goal
The problem asks to remove as few intervals as possible so that no two intervals overlap.Step 2: Clarify what non-overlapping means
Non-overlapping means for any two intervals, one ends before the other starts.Final Answer:
To remove the minimum number of intervals so that the remaining intervals do not overlap -> Option CQuick Check:
Minimum removal = non-overlapping intervals [OK]
- Confusing removal with merging intervals
- Thinking the goal is to count overlaps
- Sorting intervals without removing
Solution
Step 1: Identify sorting criteria for minimum removal
We sort intervals by their end time ascending to greedily pick intervals that finish earliest.Step 2: Check code correctness
std::sort(intervals.begin(), intervals.end(), [](auto &a, auto &b) { return a.end < b.end; }); uses a lambda comparing a.end < b.end, which is correct for sorting by end time ascending.Final Answer:
std::sort(intervals.begin(), intervals.end(), [](auto &a, auto &b) { return a.end < b.end; }); -> Option AQuick Check:
Sort by end time ascending = std::sort(intervals.begin(), intervals.end(), [](auto &a, auto &b) { return a.end < b.end; }); [OK]
- Sorting by start time instead of end time
- Sorting in descending order of end time
- Using default sort without comparator
struct Interval { int start, end; };
std::vector<Interval> intervals = {{1,3}, {2,4}, {3,5}};
std::sort(intervals.begin(), intervals.end(), [](auto &a, auto &b) { return a.end < b.end; });
int count = 0, end_time = INT_MIN;
for (auto &interval : intervals) {
if (interval.start >= end_time) {
end_time = interval.end;
} else {
count++;
}
}
std::cout << count << std::endl;Solution
Step 1: Sort intervals by end time
Sorted intervals by end: (1,3), (2,4), (3,5)Step 2: Iterate and count removals
Start with end_time = -∞ - Interval (1,3): start 1 >= -∞, keep, end_time=3 - Interval (2,4): start 2 < 3, overlap, count=1 - Interval (3,5): start 3 >= 3, keep, end_time=5Final Answer:
1 -> Option BQuick Check:
One overlap removed = 1 [OK]
- Not updating end_time correctly
- Counting non-overlapping intervals as removals
- Sorting incorrectly before iteration
std::sort(intervals.begin(), intervals.end(), [](auto &a, auto &b) { return a.start < b.start; });
int count = 0, end_time = INT_MIN;
for (auto &interval : intervals) {
if (interval.start >= end_time) {
end_time = interval.end;
} else {
count++;
}
}
return count;Solution
Step 1: Check sorting criteria
The code sorts intervals by start time, but greedy approach requires sorting by end time to minimize removals.Step 2: Understand impact on counting
Sorting by start time can cause counting more removals than needed because intervals ending earlier are not prioritized.Final Answer:
Sorting by start time instead of end time causes incorrect removal count -> Option DQuick Check:
Sort by end time, not start time [OK]
- Sorting by start time instead of end time
- Assuming INT_MIN causes overflow here
- Ignoring empty input checks
[[1,2],[2,3],[3,4],[1,3]], what is the minimum number of intervals to remove to make the rest non-overlapping?Solution
Step 1: Sort intervals by end time
Sorted intervals: [1,2], [2,3], [1,3], [3,4]Step 2: Select intervals greedily and count removals
Keep [1,2] (end=2) - [2,3]: start 2 >= 2, keep - [1,3]: start 1 < 2 (overlaps with [1,2]), remove (count=1) - [3,4]: start 3 >= 3, keep Total removals so far: 1 But [1,3] overlaps with [1,2], removing it once is enough. Check if any other removals needed: none Total removals = 1Step 3: Re-examine intervals order
Actually, sorting by end time ascending is: [1,2], [2,3], [1,3], [3,4] But [1,3] overlaps with [1,2], so removing it once suffices. If we keep [1,2], [2,3], [3,4], we remove [1,3] only once. So minimum removals = 1Final Answer:
1 -> Option AQuick Check:
Remove overlapping [1,3] only once [OK]
- Removing too many intervals unnecessarily
- Not sorting by end time
- Confusing overlapping intervals
Ready to prove it?
Pass the test and this pattern moves unknown
