Interval Scheduling¶
Problem¶
Given a collection of intervals, find the maximum number of non-overlapping intervals (activity selection problem).
Approach¶
Sort intervals by end time. Greedily select the next interval whose start time is >= the end time of the last selected interval. This maximizes the number of non-overlapping intervals.
When to Use¶
Activity selection / resource booking — "max non-overlapping intervals", "minimum removals for no overlap", "room scheduling". Sort by end time, greedily pick earliest-finishing. Aviation: gate/runway slot allocation.
Complexity¶
| Time | O(n log n) |
| Space | O(1) (excluding input sort) |
Implementation¶
interval_scheduling ¶
Interval Scheduling — maximum non-overlapping intervals.
Problem
Given a collection of intervals, find the maximum number of non-overlapping intervals (activity selection problem).
Approach
Sort intervals by end time. Greedily select the next interval whose start time is >= the end time of the last selected interval. This maximizes the number of non-overlapping intervals.
When to use
Activity selection / resource booking — "max non-overlapping intervals", "minimum removals for no overlap", "room scheduling". Sort by end time, greedily pick earliest-finishing. Aviation: gate/runway slot allocation.
Complexity
Time: O(n log n) Space: O(1) (excluding input sort)
max_non_overlapping ¶
Return the maximum number of non-overlapping intervals.
max_non_overlapping([[1, 3], [2, 4], [3, 5], [0, 6]]) 2
Source code in src/algo/greedy/interval_scheduling.py
min_removals ¶
Return the minimum number of intervals to remove for no overlap.
Equivalent to len(intervals) - max_non_overlapping(intervals).
min_removals([[1, 2], [2, 3], [3, 4], [1, 3]]) 1
Source code in src/algo/greedy/interval_scheduling.py
"""Tests for interval scheduling."""
from algo.greedy.interval_scheduling import max_non_overlapping, min_removals
class TestMaxNonOverlapping:
def test_basic(self) -> None:
assert max_non_overlapping([[1, 3], [2, 4], [3, 5], [0, 6]]) == 2
def test_no_overlap(self) -> None:
assert max_non_overlapping([[1, 2], [3, 4], [5, 6]]) == 3
def test_all_overlap(self) -> None:
assert max_non_overlapping([[1, 10], [2, 5], [3, 8]]) == 1
def test_single_interval(self) -> None:
assert max_non_overlapping([[0, 1]]) == 1
def test_empty(self) -> None:
assert max_non_overlapping([]) == 0
def test_touching_intervals(self) -> None:
assert max_non_overlapping([[1, 2], [2, 3], [3, 4]]) == 3
class TestMinRemovals:
def test_basic(self) -> None:
assert min_removals([[1, 2], [2, 3], [3, 4], [1, 3]]) == 1
def test_no_removals_needed(self) -> None:
assert min_removals([[1, 2], [3, 4]]) == 0
def test_all_same(self) -> None:
assert min_removals([[1, 2], [1, 2], [1, 2]]) == 2
Implement it yourself
Run: just challenge greedy interval_scheduling
Then implement the functions to make all tests pass.
Use just study greedy for watch mode.
Reveal Solution
interval_scheduling ¶
Interval Scheduling — maximum non-overlapping intervals.
Problem
Given a collection of intervals, find the maximum number of non-overlapping intervals (activity selection problem).
Approach
Sort intervals by end time. Greedily select the next interval whose start time is >= the end time of the last selected interval. This maximizes the number of non-overlapping intervals.
When to use
Activity selection / resource booking — "max non-overlapping intervals", "minimum removals for no overlap", "room scheduling". Sort by end time, greedily pick earliest-finishing. Aviation: gate/runway slot allocation.
Complexity
Time: O(n log n) Space: O(1) (excluding input sort)
max_non_overlapping ¶
Return the maximum number of non-overlapping intervals.
max_non_overlapping([[1, 3], [2, 4], [3, 5], [0, 6]]) 2
Source code in src/algo/greedy/interval_scheduling.py
min_removals ¶
Return the minimum number of intervals to remove for no overlap.
Equivalent to len(intervals) - max_non_overlapping(intervals).
min_removals([[1, 2], [2, 3], [3, 4], [1, 3]]) 1