Intervals
Intermediate 10 min read

Interval scheduling

In one line

To keep the most non-overlapping intervals, sort by end time and greedily take each interval that starts after the last one you took; earliest finish leaves the most room for the rest.

What it is

Interval scheduling asks: given many intervals, choose the largest set that do not overlap. Examples: the most talks one person can attend, or the fewest meetings to cancel so the rest fit (Non-overlapping Intervals, which is n minus the maximum kept).

The greedy rule is: always pick the interval that ends earliest among those compatible with what you have picked. Sorting by start or by length does not work in general; sorting by end does.

When intervals have weights (for example profit per job) the greedy fails, and you need dynamic programming with binary search: weighted interval scheduling, O(n log n).

Why interviewers ask

This is the textbook example of a greedy algorithm with a proof, and it appears as Non-overlapping Intervals, Minimum Arrows to Burst Balloons and Maximum Number of Events. Interviewers want the right sort key and a short exchange-argument explanation of why it is optimal.

How it works

  1. 1Sort intervals by end time.
  2. 2Keep last_end, the end of the most recently chosen interval, starting at minus infinity.
  3. 3For each interval in order: if its start >= last_end (half-open; use > for closed intervals that must not touch), choose it and set last_end to its end. Otherwise skip it.
  4. 4The number chosen is the maximum. The number skipped is the minimum to remove.
  5. 5Why it works (exchange argument): any optimal solution's first interval can be swapped for the earliest-ending interval without causing a conflict, because that one ends no later. Repeat for the rest, so greedy is never worse.
  6. 6Minimum arrows to burst balloons is the same sweep with closed intervals: each arrow at the current end bursts every balloon that starts at or before it.

Worked example · Non-overlapping intervals: [[1, 2], [2, 3], [3, 4], [1, 3]]

  1. Sort by end: [1, 2] (end 2), [2, 3] (end 3), [1, 3] (end 3), [3, 4] (end 4).
  2. [1, 2]: 1 >= -infinity, keep. last_end = 2. kept = 1.
  3. [2, 3]: 2 >= 2, keep. last_end = 3. kept = 2.
  4. [1, 3]: 1 < 3, overlaps, skip.
  5. [3, 4]: 3 >= 3, keep. last_end = 4. kept = 3.
  6. Kept 3 of 4, so the minimum to remove is 1 (the interval [1, 3]).

Picture it

At a festival with overlapping concerts, if you want to see as many full concerts as possible, always pick the next concert that finishes soonest. Finishing early leaves the most evening left for the others.

Reference code

def erase_overlap_intervals(intervals):
    # keep as many non-overlapping intervals as possible,
    # return how many must be removed
    intervals = sorted(intervals, key=lambda x: x[1])  # by END time
    kept = 0
    last_end = float("-inf")
    for start, end in intervals:
        if start >= last_end:           # fits after the last kept one
            kept += 1
            last_end = end
    return len(intervals) - kept

print(erase_overlap_intervals([[1, 2], [2, 3], [3, 4], [1, 3]]))  # 1

Sorting by end and keeping every interval that starts at or after the last kept end gives the maximum number of non-overlapping intervals; the rest must be removed. Touching intervals like [1, 2] and [2, 3] are treated as compatible.

Key patterns

Earliest end first

When: Maximise the number of non-overlapping intervals

How: Sort by end; keep if start >= last kept end.

Minimum removals

When: Non-overlapping Intervals

How: Answer = n - maximum kept.

Minimum points to stab all intervals

When: Burst balloons with arrows

How: Sort by end; shoot at the end of the first unburst balloon; skip all balloons with start <= that point.

Weighted scheduling

When: Each interval has a value

How: Sort by end; dp[i] = max(dp[i - 1], value[i] + dp[p(i)]), where p(i) is the last interval ending by start[i], found with binary search.

Real-world use

Single-resource booking

Systems that accept as many requests as possible on one machine, one operating theatre or one ad slot without conflicts use earliest-finish-first when all requests are worth the same.

Ad and broadcast scheduling

TV and digital-signage schedulers fill a single channel with non-overlapping slots; when slots have different values they switch to the weighted DP version.

Job scheduling with profits

Freelance and cloud spot-job planners that choose which paid jobs to accept on one worker solve weighted interval scheduling: sort by end, and for each job binary-search the last compatible job.

In a project

A conference app lets attendees star talks; many overlap, and attendees want a personal agenda that includes as many full talks as possible.

  1. Take the starred talks as half-open [start, end) intervals.
  2. Sort by end time and greedily keep each talk that starts at or after the last kept talk ends.
  3. Show the kept talks as the agenda and the skipped ones as 'conflicts', with the overlapping kept talk named.
  4. If attendees can rate talks, switch to weighted interval scheduling (DP plus binary search) to maximise total rating instead of count.

Impact: Each attendee gets a provably maximal agenda instantly, conflicts are explained instead of hidden, and the same code handles thousands of attendees in milliseconds each.

Trade-offs

Use it when

  • All intervals are worth the same and there is one resource
  • You need the maximum compatible set or the minimum removals
  • You need the fewest points that hit every interval

Avoid it when

  • Intervals have different weights: use DP with binary search
  • There are several resources (rooms): count peaks with a sweep or assign with a heap
  • Intervals have deadlines and durations but flexible start times: that is a different scheduling problem

Cost: O(n log n) time for the sort, O(1) extra space for the sweep. Weighted version: O(n log n) time, O(n) space.

Common mistakes

  • Sorting by start time: a long interval that starts first blocks many short ones.
  • Sorting by shortest length: a short interval can overlap two others that are compatible with each other.
  • Using greedy for the weighted version.
  • Getting the touching rule wrong: balloons use closed intervals (touching counts as overlap), while meeting-style problems treat touching as compatible.
  • Not being able to explain why earliest end is optimal.

Interview questions

Quick revision

  • Max non-overlapping: sort by END, keep if start >= last_end.
  • Min removals = n - max kept.
  • Proof: exchange argument (earliest end never hurts).
  • Sort by start or by length: wrong.
  • Arrows/balloons: closed intervals, start <= arrow means burst.
  • Weighted: DP + binary search, O(n log n).
  • Greedy version: O(n log n) time, O(1) extra space.

Check yourself

1. To maximise the number of non-overlapping intervals, sort by:

2. Intervals [[1, 10], [2, 3], [4, 5], [6, 7]]. What is the maximum number of non-overlapping intervals?

3. Jobs have different profits. Does earliest-end greedy maximise total profit?

4. Balloons [[1, 6], [2, 8], [7, 12], [10, 16]]. Minimum arrows?

Saved on this device. Create a free account to keep it on every device.

Practise this with Sam

A real mock interview, out loud, with an honest scorecard. Free to start.

Start free