Non-overlapping Intervals
Master this topic with zero to advance depth.
Non-overlapping Intervals
Given an array of intervals intervals where intervals[i] = [start_i, end_i], return the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping.
Visual Representation
Intervals: [[1,2], [2,3], [3,4], [1,3]]
1--2
2--3
3--4
1-----3
To keep most intervals (3), we must remove [1,3].
Result: 1Examples
[1,3] can be removed and the rest of intervals are non-overlapping.
Level I: Recursive Selection (Brute Force)
Intuition
The problem asks for the minimum removals to remove all overlaps. This is equivalent to finding the maximum number of non-overlapping intervals. We can generate all combinations of intervals (take it or leave it) and find the maximum valid set.
Thought Process
- Sort the intervals by
starttime so we can easily check for overlaps sequentially. - For each interval at
currIndex, we have two choices:- Include it: Only possible if it doesn't overlap with the last included interval
prevIndex(i.e.,intervals[prevIndex].end <= intervals[currIndex].start). We add 1 to our count and move tocurrIndex + 1. - Exclude it: We move to
currIndex + 1without adding to our count.
- Include it: Only possible if it doesn't overlap with the last included interval
- Return the maximum of these two choices for all steps.
Detailed Dry Run
intervalsSorted = [[1,2], [1,3], [2,3]]
- solve(-1, 0):
- Take [1,2]: 1 + solve(0, 1) -> 1 + 1 (takes [2,3]) = 2
- Leave [1,2]: solve(-1, 1) -> max(take[1,3], leave[1,3]) = 1 Max kept = 2. Removals = 3 - 2 = 1.
Level II: Dynamic Programming (LIS Variation)
Intuition
This problem is equivalent to finding the Longest Chain of Pairs or the Longest Increasing Subsequence. We want to find the maximum number of intervals k that can be kept. Then the result is N - k.
Thought Process
- Sort the intervals by
starttime. - Create a
dparray wheredp[i]is the maximum number of non-overlapping intervals ending at indexi. - For each
i, look at allj < i. Ifintervals[j].end <= intervals[i].start, then we can extend the chain:dp[i] = max(dp[i], dp[j] + 1).
Pattern: Dynamic Programming / LIS
Detailed Dry Run
intervalsSorted = [[1,2], [1,3], [2,3]], dp=[1,1,1]
- i=1 [1,3]: j=0 [1,2] overlaps. dp[1]=1.
- i=2 [2,3]: j=0 [1,2] no overlap. dp[2]=max(1, dp[0]+1)=2.
- i=2 [2,3]: j=1 [1,3] overlaps. dp[2]=2. Max kept = 2. Removals = 3 - 2 = 1.
Level III: Optimal Greedy (Sort by End)
Intuition
To keep the maximum number of intervals, we should always pick the interval that ends the earliest. This is the classic Interval Scheduling problem. Why? Because an earlier end time leaves the most possible room for subsequent intervals.
Thought Process
- Sort by
endpoint. - Keep track of the
lastEndtime of the last accepted interval. - For each interval:
- If
start >= lastEnd, accept it and updatelastEnd. - Else, it overlaps; increment
removalscount.
- If
Pattern: Interval Scheduling
Detailed Dry Run
intervals = [[1,2], [2,3], [3,4], [1,3]] After Sort: [[1,2], [2,3], [1,3], [3,4]]
| Step | Interval | Range | lastEnd | Action |
|---|---|---|---|---|
| 1 | [1, 2] | [1, 2] | 2 | Keep [1,2]. lastEnd = 2 |
| 2 | [2, 3] | [2, 3] | 3 | 2 >= 2? YES. Keep [2,3]. lastEnd = 3 |
| 3 | [1, 3] | [1, 3] | 3 | 1 < 3? NO. Remove [1,3]. |
| 4 | [3, 4] | [3, 4] | 4 | 3 >= 3? YES. Keep [3,4]. lastEnd = 4 |
Result: 1 removal.
Found an issue or have a suggestion?
Help us improve! Report bugs or suggest new features on our Telegram group.