Interval scheduling finds max non-overlapping meetings using earliest finish time greedy
Minimum meeting rooms: sort starts, track active end times with a min-heap
Merge intervals: sort starts, merge consecutive overlaps in a single pass
All three run O(n log n): the sort dominates
Production trap: assuming sorting by start time works for max intervals — it does not
✦ Definition~90s read
What is Interval Scheduling and Meeting Rooms Problem?
Interval scheduling is a class of optimization problems where you have a set of intervals (start time, end time) and need to select, arrange, or process them under constraints like non-overlap or resource limits. It’s a classic greedy algorithm proving ground because the canonical problem—maximizing non-overlapping intervals—has a simple O(n log n) solution using earliest finish time.
★
You have a list of meetings, each with a start and end time.
But that’s a trap: the greedy approach works only for unweighted intervals. Real-world systems (e.g., calendar conflict resolution, CPU task scheduling, meeting room allocation) often hit O(n²) blowups when they naively compare every pair of intervals, leading to 30-second timeouts at scale.
The core tension is between the elegant greedy solution for the basic case and the combinatorial explosion when you add weights, constraints, or need to merge/partition intervals efficiently.
In practice, interval scheduling appears in three common flavors. Problem 1 (Maximum Non-Overlapping Intervals) is the textbook greedy: sort by end time, pick the earliest finisher, skip overlaps. Problem 2 (Minimum Meeting Rooms) requires a sweep-line approach—track concurrent intervals with a min-heap, O(n log n).
Problem 3 (Merge Overlapping Intervals) sorts by start time and merges in one pass. Each has a clean O(n log n) solution, but the moment you introduce weights (e.g., profit per interval), the greedy fails and you need dynamic programming with binary search for O(n log n) or fall back to O(n²).
The trap is assuming the greedy pattern generalizes—it doesn’t, and that’s where production systems get bitten.
When not to use interval scheduling: if your intervals are sparse or have irregular constraints (e.g., variable resource costs, preemption, dependencies), a general constraint solver or custom DP is safer. For weighted intervals, never use greedy—you’ll get wrong answers.
The 30-second timeout scenario typically arises from O(n²) pairwise overlap checks in naive implementations (e.g., nested loops for meeting room allocation). The fix is always to sort and use a heap or sweep line. Tools like Google OR-Tools or custom DP handle the weighted case, but for unweighted, stick with the O(n log n) greedy—just don’t cargo-cult it into weighted problems.
Plain-English First
You have a list of meetings, each with a start and end time. Two problems: (1) What is the maximum number of non-overlapping meetings you can attend? (2) What is the minimum number of rooms needed to host all meetings simultaneously? Both have elegant greedy solutions.
⚙ Browser compatibility
Latest versions — ✓ supported
Chrome
Firefox
Safari
Edge
✓
✓
✓
✓
Interval scheduling appears in every operating system (process time slots), every calendar application (meeting conflict detection), and virtually every resource allocation problem. The three variants — maximise non-overlapping intervals, minimise rooms needed, merge overlapping intervals — are among the most frequently asked algorithmic interview problems at top companies.
All three have elegant O(n log n) greedy solutions, but the correctness argument for each is different. Maximum non-overlapping uses earliest deadline first with an exchange argument. Minimum rooms uses a priority queue sweep. Merge intervals is just careful iteration. Knowing all three and why each works — not just what to code — is what distinguishes thorough preparation.
Why Interval Scheduling Is a Greedy Trap
Interval scheduling is the problem of selecting the maximum number of non-overlapping intervals from a set, each defined by a start and end time. The core mechanic: given intervals (s_i, f_i), choose the largest subset where no two intervals overlap. The canonical greedy solution sorts by finish time and picks the earliest-finishing compatible interval — O(n log n) and optimal.
What matters in practice: the greedy algorithm works only when intervals are unweighted. Weighted interval scheduling requires dynamic programming — O(n²) naive, O(n log n) with binary search. The key property is compatibility: two intervals i and j overlap if s_i < f_j and s_j < f_i. The DP recurrence builds on the last compatible interval before each job, which is where the O(n²) blowup hides if you don't precompute.
Use interval scheduling whenever you need to maximize throughput under exclusive resource access — CPU scheduling, meeting room allocation, bandwidth reservation. It matters because the naive DP is deceptively expensive: 10,000 intervals can produce 100 million compatibility checks, turning a 10ms problem into a 30-second timeout in production.
⚠ Greedy ≠ Optimal for Weighted
The classic greedy by finish time fails on weighted intervals — you must use DP. Many teams learn the greedy solution and apply it blindly to weighted variants.
📊 Production Insight
A real-time ad server used greedy scheduling for weighted ad slots, causing revenue loss because high-value ads were dropped.
Symptom: 15% revenue drop with no errors — only visible when comparing fill rates per ad tier.
Rule: If intervals carry different weights, never use unweighted greedy — always verify the problem variant before choosing the algorithm.
🎯 Key Takeaway
Unweighted interval scheduling is O(n log n) greedy by finish time — optimal and fast.
Weighted interval scheduling requires DP with binary search for O(n log n) — naive O(n²) kills performance.
Always precompute the last compatible interval index to avoid O(n²) compatibility checks in DP.
thecodeforge.io
Interval Scheduling Problem
Problem 1 — Maximum Non-Overlapping Intervals
Greedy insight: always pick the interval that finishes earliest. This leaves maximum room for future intervals.
interval_scheduling.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
defmax_non_overlapping(intervals: list[tuple]) -> list[tuple]:
"""
Returns maximum set of non-overlapping intervals.
Greedy: sort by end time, always pick earliest finish.
"""
intervals = sorted(intervals, key=lambda x: x[1])
selected = []
last_end = float('-inf')
for start, end in intervals:
if start >= last_end: # no overlap
selected.append((start, end))
last_end = end
return selected
intervals = [(1,4),(3,5),(0,6),(5,7),(3,9),(5,9),(6,10),(8,11),(8,12),(2,14),(12,16)]
result = max_non_overlapping(intervals)
print(f'Max non-overlapping: {len(result)} → {result}')
Merging intervals is commonly used in calendar apps to collapse busy slots.
A bug creeps in when intervals are abutting: does [1,4] and [4,5] merge?
The merge condition 'start <= last_end' merges them. If the spec says non-abutting, use '<'.
Always clarify the edge case with your interviewer or product manager.
🎯 Key Takeaway
Sort by start time, linear scan.
Merge if next start <= current end.
O(n log n) for sort, O(n) for merge.
Why Earliest Finish Time is Optimal
Claim: picking the interval with the earliest finish time is always in some optimal solution. Proof: suppose optimal starts with interval A instead of E (earliest finish). Replace A with E — since E finishes earlier, this can only improve future compatibility. By induction, greedy is optimal.
📊 Production Insight
The exchange argument is the standard formal proof for greedy interval scheduling.
In practice, engineers often skip the proof and just trust the pattern — that's fine until someone asks 'why' in a design review.
Knowing the proof separates senior from mid-level.
🎯 Key Takeaway
Earliest finish time wins because it leaves the most room.
Exchange argument: swap any optimal first choice with the earliest-finisher.
It never makes the solution worse — therefore greedy is optimal.
When Greedy Fails — Weighted Interval Scheduling
The earliest finish time greedy does NOT work when intervals have weights (values). A short, high-value interval might be later than a long, low-value one. For weighted interval scheduling you need dynamic programming: 1. Sort by end time 2. Use DP[i] = max(weight[i] + DP[p(i)], DP[i-1]) where p(i) is the last interval non-overlapping with i. This is O(n log n) with binary search for p(i).
weighted_interval_scheduling.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
defweighted_interval_scheduling(intervals: list[tuple]) -> int:
# intervals: list of (start, end, weight)
intervals = sorted(intervals, key=lambda x: x[1]) # sort by end
n = len(intervals)
# binary search for last non-overlapping intervaldeflast_non_overlap(i):
lo, hi = 0, i - 1while lo <= hi:
mid = (lo + hi) // 2if intervals[mid][1] <= intervals[i][0]:
lo = mid + 1else:
hi = mid - 1return hi
dp = [0] * n
dp[0] = intervals[0][2]
for i inrange(1, n):
include = intervals[i][2]
j = last_non_overlap(i)
if j != -1:
include += dp[j]
dp[i] = max(include, dp[i-1])
return dp[-1]
Weighted scheduling appears in profit optimisation for ad slots, resource reservations, etc.
The binary search inside DP is often forgotten in interviews — they implement O(n^2) DP which times out on 10^5 intervals.
Always lead with O(n log n) when weights are involved.
🎯 Key Takeaway
Greedy fails when intervals have weights.
Use DP with binary search for O(n log n) weighted scheduling.
The transition: dp[i] = max(include i + dp[p(i)], exclude i).
Common Techniques — Because Sorting Isn't a Personality
Interval problems look cute until you're three hours into a bug where your merge logic misses an edge case. The truth is there are maybe four patterns that cover 90% of what you'll see. Memorize them, don't worship them.
Sorting is the obvious one. You sort by start time when you need to chain intervals forward — merging, room counting, overlap detection. You sort by end time when you want to maximize count (earliest finish wins). If you don't know which axis to sort on, you haven't understood the problem's constraint.
Sweep line is the nuclear option. You flatten every interval into start/end events, then walk the timeline tallying active intervals. It's overkill for simple merge, but it's the only sane way to find peak overlap or handle point queries.
Prefix sums and segment trees? Those are for when your intervals aren't cheap O(n log n) sorted scans. If you're reaching for a segment tree in an interview, you better be solving range queries over mutable intervals, not a glorified calendar merge. Don't confuse sophistication with necessity.
SweepLineOverlap.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// io.thecodeforge — dsa tutorialimport java.util.*;
publicclassSweepLineOverlap {
// Find maximum overlapping intervals at any pointpublicstaticintmaxOverlap(int[][] intervals) {
List<int[]> events = newArrayList<>();
for (int[] iv : intervals) {
events.add(new int[]{iv[0], 1}); // start
events.add(new int[]{iv[1], -1}); // end
}
events.sort((a, b) -> a[0] != b[0]
? Integer.compare(a[0], b[0])
: Integer.compare(a[1], b[1]));
int active = 0, maxCount = 0;
for (int[] e : events) {
active += e[1];
maxCount = Math.max(maxCount, active);
}
return maxCount;
}
publicstaticvoidmain(String[] args) {
int[][] meetings = {{1,5}, {2,6}, {3,7}, {4,8}};
System.out.println(maxOverlap(meetings));
}
}
Output
4
💡Senior Shortcut:
When sweep line sorts events, always break ties by ending before starting. Handles zero-length intervals without extra edge-case code.
🎯 Key Takeaway
Sort by the right axis: start for merging, end for counting. Sweep line for peak overlap. Never use a segment tree unless you mutating intervals.
thecodeforge.io
Interval Scheduling Problem
Identifying Problems Involving Interval Manipulation — Read the Tell
Most interval problems announce themselves with specific language. If you hear "meetings," "appointments," "schedules," or "time slots," you're in interval territory. But the real giveaway is the operation: merge, count, find free time, or calculate duration of overlap.
There's a subtler pattern too. Any problem that gives you pairs of numbers and asks for something about "non-overlapping" or "maximum set" is almost certainly an interval scheduling variant. The moment you see a conflict detection between two ranges, stop pretending it's a geometry problem and sort the damn intervals.
What trips up juniors is disguised intervals. A problem might hand you server start times and durations — you need to compute end times yourself. Or it gives you string timestamps and wants the busiest hour. That's still intervals, just wrapped in parsing. Don't fall for the dressing. Strip it down to [start, end) and apply your tools.
If you find yourself writing three nested loops to compare every interval pair with every other — stop. You missed the pattern. Go back to the problem statement. Look for the operation keyword. Then sort, greedy, or sweep line. That's your playbook.
DisguisedIntervals.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// io.thecodeforge — dsa tutorialimport java.util.*;
publicclassDisguisedIntervals {
// Servers start at given times, run for given durations.// Find the minute with most servers running.publicstaticintpeakServerLoad(int[] startTime, int[] duration) {
int n = startTime.length;
int[][] intervals = newint[n][2];
for (int i = 0; i < n; i++) {
intervals[i][0] = startTime[i];
intervals[i][1] = startTime[i] + duration[i];
}
// Now it's clearly an interval problem — sweep lineList<int[]> events = newArrayList<>();
for (int[] iv : intervals) {
events.add(newint[]{iv[0], 1});
events.add(newint[]{iv[1], -1});
}
events.sort((a, b) -> a[0] != b[0]
? Integer.compare(a[0], b[0])
: Integer.compare(a[1], b[1]));
int active = 0, peak = 0;
for (int[] e : events) {
active += e[1];
peak = Math.max(peak, active);
}
return peak;
}
publicstaticvoidmain(String[] args) {
int[] starts = {0, 2, 5};
int[] durations = {10, 3, 5};
System.out.println(peakServerLoad(starts, durations));
}
}
Output
2
🔥Common Pitfall:
Don't start coding until you've converted all inputs to a consistent interval representation. Raw timestamps or durations are not intervals — [start, end) is.
🎯 Key Takeaway
Keywords like schedule, overlap, busy, load, or free slot signal an interval problem. Convert everything to [start, end) before you touch a loop.
API endpoint for scheduling recommendations returned HTTP 504 after 30 seconds during peak hours.
Assumption
Developers assumed O(n^2) was acceptable because 'it's just meetings' and never tested with real data volume.
Root cause
The implementation compared every interval against every other interval to find conflicts, resulting in a quadratic blowup when users imported their entire Outlook calendar.
Fix
Replaced the pairwise check with a sweep-line algorithm: sort by start time, track the earliest end time via a min-heap. Runtime dropped from O(n^2) to O(n log n).
Key lesson
Always profile with production-like data volumes before assuming algorithm choice is irrelevant.
Interval scheduling problems often feel small — but calendars grow fast.
When you see an O(n^2) algorithm in an interview solution, that's a red flag.
Production debug guideSymptom -> Action patterns for common bugs3 entries
Symptom · 01
Algorithm returns fewer non-overlapping intervals than expected
→
Fix
Verify the sort key is end time, not start time. Then manually trace the greedy selection on a small custom set — many bugs hide in edge cases like abutting intervals (end == next start).
Symptom · 02
Minimum rooms calculation returns too many rooms
→
Fix
Check that the heap comparison uses '<= start' (allowing reuse when a meeting ends exactly when another starts). If you use '<', you'll overcount rooms by one for abutting meetings.
Symptom · 03
Merged intervals are incorrect for adjacent intervals
→
Fix
Decide whether [1,4] and [4,5] should merge. The problem statement defines 'overlap' inclusively or exclusively. Adjust the merge condition accordingly (<= vs <).
Interval Scheduling Variants Compared
Problem
Sort Key
Data Structure
Time Complexity
Key Insight
Max Non-Overlapping
End time
None
O(n log n)
Earliest finish first
Min Meeting Rooms
Start time
Min-heap (end times)
O(n log n)
Sweep over start times, heap tracks active endings
sort by END time (not start time — this is the common mistake), pick greedily. Sorting by start time gives a suboptimal result.
2
Min meeting rooms
sort by start time, use a min-heap of end times. Size of heap at any point = rooms in use. Peak heap size = answer.
3
Merge intervals
sort by start time, linear scan — merge if next start <= current end. O(n log n) for sort, O(n) for merge.
4
Why earliest deadline works
if you could improve by not taking the earliest-finishing interval first, you could swap it in — but swapping never makes things worse. Exchange argument.
5
LeetCode connection
435 (non-overlapping), 252/253 (meeting rooms), 56 (merge intervals). These four problems cover 80% of interval scheduling interview questions.
6
Weighted intervals require DP
greedy fails.
Common mistakes to avoid
4 patterns
×
Sorting by start time for max non-overlapping intervals
Symptom
Algorithm returns a suboptimal set — it picks the earliest start (which may be a long interval that blocks many later intervals).
Fix
Always sort by end time. The greedy that picks earliest finish is provably optimal.
×
Using '<' instead of '<=' when checking overlap for meeting rooms
Symptom
Minimum room count is off by one for abutting meetings (e.g., [0,5] and [5,10]). The algorithm allocates an extra room because it doesn't consider that the first meeting ends exactly when the second starts.
Fix
Use '<=' when comparing heap[0] <= start to allow reusing the room when the earlier meeting ended exactly at the start of the next.
×
Merging intervals without clarifying overlap definition
Symptom
Merged intervals either include or exclude abutting pairs inconsistently, causing bugs in downstream calendar displays.
Fix
Explicitly ask: do [1,4] and [4,5] overlap? If yes, condition is 'start <= last_end'. If no, condition is 'start < last_end'.
×
Applying greedy to weighted interval scheduling
Symptom
Returns incorrect maximum profit because greedy ignores weights.
Fix
Recognise that weighted interval scheduling requires DP. Greedy only works when all intervals have equal weight (or when only count matters).
Why does sorting by end time give the optimal solution for interval sche...
Q02SENIOR
How does the min-heap approach solve the minimum meeting rooms problem?
Q03SENIOR
What is the difference between interval scheduling maximisation and mini...
Q04JUNIOR
How would you find the minimum number of intervals to remove to make the...
Q05SENIOR
What if intervals have weights (profits)? How would you solve it?
Q01 of 05SENIOR
Why does sorting by end time give the optimal solution for interval scheduling?
ANSWER
Because the earliest finishing interval leaves the most room for the rest. Formally, an exchange argument shows that if an optimal solution starts with interval A instead of the earliest-finish interval E, you can replace A with E without reducing the total count — E finishes no later than A, so it can't block more intervals. By induction, there's always an optimal solution that includes the earliest finisher.
Q02 of 05SENIOR
How does the min-heap approach solve the minimum meeting rooms problem?
ANSWER
We sweep from earliest start to latest. For each meeting, we check if the room (heap) of the earliest-ending active meeting is free (heap[0] <= start). If yes, we reuse that room by replacing its end time with the current meeting's end time. If not, we add a new room. The heap size at any moment is the number of concurrent meetings, and the maximum heap size over the sweep is the answer.
Q03 of 05SENIOR
What is the difference between interval scheduling maximisation and minimum room allocation?
ANSWER
Maximisation finds the largest set of non-overlapping intervals — you skip conflicts, aiming to attend as many as possible. Minimum rooms asks: 'if you must schedule all intervals, how many rooms do you need?' It's an online resource allocation problem using a sweep line and heap. They are dual problems but solved with different greedy strategies.
Q04 of 05JUNIOR
How would you find the minimum number of intervals to remove to make the rest non-overlapping?
ANSWER
That's equivalent to finding the maximum non-overlapping set (LeetCode 435). The minimum removals = total intervals - max non-overlapping. Use the greedy earliest-finish algorithm to get the max non-overlapping set, then subtract from total count.
Q05 of 05SENIOR
What if intervals have weights (profits)? How would you solve it?
ANSWER
Use dynamic programming. Sort intervals by end time. Let dp[i] = max profit using first i intervals. For interval i, find the last interval j that ends before interval i starts (binary search). Then dp[i] = max(weight[i] + dp[j], dp[i-1]). Complexity O(n log n).
01
Why does sorting by end time give the optimal solution for interval scheduling?
SENIOR
02
How does the min-heap approach solve the minimum meeting rooms problem?
SENIOR
03
What is the difference between interval scheduling maximisation and minimum room allocation?
SENIOR
04
How would you find the minimum number of intervals to remove to make the rest non-overlapping?
JUNIOR
05
What if intervals have weights (profits)? How would you solve it?
SENIOR
FAQ · 4 QUESTIONS
Frequently Asked Questions
01
Is sorting by start time or end time correct for max non-overlapping?
End time. Sorting by start time is a common mistake — it doesn't give optimal results. Example: [(0,100),(1,2),(3,4)] — earliest start is (0,100) which blocks everything; earliest finish (1,2) is much better.
Was this helpful?
02
Can I solve the minimum meeting rooms problem without a heap?
Yes: separate starts and ends, sort both arrays, then use a two-pointer scan to count overlapping intervals. That's O(n log n) time and O(n) space, but less intuitive than the heap approach.
Was this helpful?
03
What if intervals are already sorted?
For max non-overlapping, if sorted by end time you can do O(n). For meeting rooms, if sorted by start time, the heap logic remains O(n log n) overall because heap operations dominate — but you skip the sort cost.
Was this helpful?
04
How do I handle intervals that are inclusive on both ends?
If intervals are [start, end] inclusive, then two intervals [1,4] and [4,5] overlap because 4 is shared. Use <= for overlap detection. If exclusive, use <. The algorithm adjusts accordingly.