Non-overlapping Intervals and the End Time Greedy
"Non-overlapping Intervals" is a Medium-level staple in Meta, Amazon, Bloomberg loops, and it is a textbook fit for the Merge Intervals pattern — one of the nine patterns that cover the bulk of what FAANG coding interviews actually test. Part 3 of 11 in the Merge Intervals arc.
The Problem
Given intervals, return the minimum number to remove so the rest are mutually non-overlapping. Touching intervals do not overlap here. This is the interval version of activity selection — the one greedy proof every candidate should be able to sketch.
Input: intervals = [[1, 2], [2, 3], [3, 4], [1, 3]]
Output: 1
Remove [1, 3]; the rest are disjoint.
Recognizing the Merge Intervals Pattern
Interval problems — scheduling, calendars, resource booking — almost all reduce to one move: sort by start (or end), then sweep once while comparing each interval against a running boundary. Overlap exists when the next start is at most the current end. Sort plus linear sweep, O(n log n), is the backbone of the entire family.
Minimize removals equals maximize kept intervals — a scheduling maximization. The classic result: sorting by end time and always keeping the earliest-ending compatible interval is optimal, because an earlier end leaves no less room for the future than any alternative.
The Approach
Sort by end. Track the end of the last kept interval. For each interval, keep it if its start is at least the tracked end; otherwise count a removal. The exchange argument — any optimal solution can swap its first pick for the earliest-ending one without loss — justifies the greed in two sentences.
Sorting by start and greedily dropping the longer of any overlapping pair also works, but the end-time version is cleaner to defend under questioning.
Python Solution
def erase_overlap_intervals(intervals: list[list[int]]) -> int:
"""Minimum removals to make all intervals pairwise disjoint."""
if not intervals:
return 0
intervals.sort(key=lambda iv: iv[1]) # earliest end first
removals = 0
last_end = intervals[0][1]
for start, end in intervals[1:]:
if start >= last_end:
last_end = end # compatible: keep
else:
removals += 1 # overlap: drop this one
return removals
Complexity
- Time: O(n log n) — sort, then linear sweep
- Space: O(1) — a counter and one boundary value beyond the in-place sort
Interview Tips and Follow-Ups
- Rehearse the exchange argument aloud — 'why sort by end?' is guaranteed, and hand-waving it downgrades an otherwise perfect answer.
- Touching intervals ([1, 2], [2, 3]) are compatible here but merged in Merge Intervals — comparing the two conventions shows command of the family.
- Identical siblings: Minimum Arrows (later in this arc) and Activity Selection — one greedy, three phrasings.
That wraps part 3 of the Merge Intervals arc. The full Technical Interview category maps all one hundred questions to the nine patterns that dominate FAANG screens — work through an arc end to end and the next unseen variant will feel familiar.
Keep reading
Car Pooling: Difference Arrays Meet Interval Events
Capacity checking with +passengers/−passengers events on a number line. Python solution and complexity analysis for the merge intervals interview pattern.
Employee Free Time: Gaps in a Merged Union of Schedules
Common free intervals across k schedules — flatten, merge, read the gaps. Python solution and complexity analysis for the merge intervals interview pattern.
Insert Interval Without Re-Sorting Anything
Exploit existing sortedness: before, absorb, after — three phases. Python solution and complexity analysis for the merge intervals interview pattern.
Newsletter
New posts, straight to your inbox
One email per post. No spam, no tracking pixels, unsubscribe anytime.
Comments
- No comments yet. Be the first.