Solving tips
- Sort by start time, then any overlap must show up between adjacent meetings, so a single O(n log n) pass over neighbors finds every conflict.
- Compare each meeting's start against the previous end; conflict when cur_start < prev_end.
- These are half-open intervals, so use strict '<' not '<=': back-to-back meetings like [1,5] and [5,8] do NOT conflict.
- Target O(n log n) time, O(1) extra space; the sort is what makes the local neighbor check valid, so never scan the raw input order.
Problem
You are given a list of meetings, each described as a pair [start, end) β the meeting occupies the half-open time range from start up to (but not including) end. One person wants to attend every meeting on the list. Decide whether that is possible: return True if no two meetings overlap in time, and False otherwise.
Two meetings that merely touch β one ends at exactly the moment the next begins β do not conflict.
Examples
intervals = [[0,30],[5,10],[15,20]] β False β the meeting [0,30] is still running when both [5,10] and [15,20] start.
intervals = [[7,10],[2,4]] β True β [2,4] finishes before [7,10] begins.
intervals = [[1,5],[5,8]] β True β the first ends exactly when the second starts; back-to-back is fine.
Constraints
0 <= len(intervals) <= 10^4
0 <= start < end <= 10^6
With up to 10^4 meetings, an O(n^2) pairwise check is borderline; O(n log n) is the expected bar.
Think about it first
Hint 1
TL;DR
Sort by start time, then check each adjacent pair β O(n log n) time, O(1) extra space (beyond the sort).
Approach 1 β Brute force
Check every pair of meetings for overlap. Two half-open intervals [a, b) and [c, d) overlap exactly when each one starts before the other ends: a < d and c < b.
from typing import List
class Solution:
def canAttendMeetings(self, intervals: List[List[int]]) -> bool:
n = len(intervals)
for i in range(n):
for j in range(i + 1, n):
a, b = intervals[i]
c, d = intervals[j]
if a < d and c < b:
return False
return True
Complexity: O(n^2) time, O(1) space.
With n = 10^4 that is ~5Γ10^7 pair checks β it may squeak by, but it does quadratic work for a question that only needs the intervals put in order once.
Approach 2 β Sort + adjacent scan
The insight: once meetings are sorted by start time, any overlap must show up between neighbors. If meeting i overlaps some later meeting j, then it certainly overlaps meeting i+1, because i+1 starts no later than j does. So after sorting, one pass over adjacent pairs finds every conflict.
from typing import List
class Solution:
def canAttendMeetings(self, intervals: List[List[int]]) -> bool:
intervals.sort(key=lambda it: it[0])
for i in range(1, len(intervals)):
prev_end = intervals[i - 1][1]
cur_start = intervals[i][0]
if cur_start < prev_end:
return False
return True
Walkthrough on [[0,30],[5,10],[15,20]]:
- Sort by start β
[[0,30],[5,10],[15,20]] (already sorted).
i = 1: previous ends at 30, current starts at 5. 5 < 30 β conflict β return False.
And on [[1,5],[5,8]]: i = 1 compares start 5 against previous end 5; 5 < 5 is false, so the loop finishes and we return True β touching endpoints are correctly allowed.
Complexity: O(n log n) time for the sort, O(1) extra space (Pythonβs sort uses O(n) internally, O(log n) typical accounting; the scan itself is O(1)).
Common pitfalls
- Using
<= instead of < in the conflict test β that wrongly rejects back-to-back meetings like [1,5] and [5,8].
- Comparing only
intervals[i] against intervals[0] after sorting, instead of against its immediate predecessor.
- Forgetting to sort at all and scanning adjacent pairs of the input order β the check is only valid on sorted data.
- Writing the pairwise overlap test as
a <= d and c <= b (closed intervals) when the problem treats end times as exclusive.
Pattern takeaway
Sorting intervals by start time collapses a global βdoes anything overlap anything?β question into a local βdoes each interval overlap its neighbor?β question. Almost every intervals problem starts with this sort; what varies is what you track while sweeping β here just the previous end time.