Interval Algorithm Patterns
Interval problems appear constantly in coding interviews — at Google, Meta, Airbnb, and Uber. The key skill: recognizing the overlap condition and knowing when to sort by start vs end time. Most interval problems reduce to one of five patterns.
Overlap Detection
Two intervals [a, b] and [c, d] overlap if and only if: a < d AND c < b (open intervals). For closed intervals [a, b] and [c, d]: a <= d AND c <= b. They do NOT overlap if: b <= c OR d <= a (one ends before the other starts). This single condition is the foundation for all interval algorithms.
Pattern 1: Merge Intervals (LC 56)
def merge(intervals: list[list[int]]) -> list[list[int]]:
intervals.sort(key=lambda x: x[0]) # sort by start time
merged = [intervals[0]]
for start, end in intervals[1:]:
if start <= merged[-1][1]: # overlaps with last merged
merged[-1][1] = max(merged[-1][1], end) # extend end
else:
merged.append([start, end]) # no overlap: add new interval
return merged
Time O(n log n) for sort, O(n) for merge. The condition start <= merged[-1][1] catches both overlap and touching intervals ([1,3],[3,5] → [1,5]).
Pattern 2: Insert Interval (LC 57)
def insert(intervals: list[list[int]], new_interval: list[int]) -> list[list[int]]:
result = []
i = 0
n = len(intervals)
new_start, new_end = new_interval
# Add all intervals that end before new_interval starts
while i < n and intervals[i][1] < new_start:
result.append(intervals[i])
i += 1
# Merge all overlapping intervals
while i < n and intervals[i][0] <= new_end:
new_start = min(new_start, intervals[i][0])
new_end = max(new_end, intervals[i][1])
i += 1
result.append([new_start, new_end])
# Add remaining intervals
result.extend(intervals[i:])
return result
Time O(n), no sorting needed since intervals are already sorted. Three passes: before, overlap, after.
Pattern 3: Non-Overlapping Intervals — Minimum Removals (LC 435)
Greedy: sort by end time. Keep an interval if it doesn’t overlap with the previous kept interval. This is the classic “Activity Selection” problem — greedily pick intervals that end earliest to leave room for future intervals.
def erase_overlap_intervals(intervals: list[list[int]]) -> int:
if not intervals:
return 0
intervals.sort(key=lambda x: x[1]) # sort by END time (key insight!)
kept = 0
last_end = float('-inf')
for start, end in intervals:
if start >= last_end: # no overlap with last kept interval
kept += 1
last_end = end
return len(intervals) - kept # removals = total - kept
Why sort by end? Sorting by start doesn’t work — an interval that starts first but ends very late blocks many future intervals. Ending earliest gives the most room for remaining intervals.
Pattern 4: Meeting Rooms II — Minimum Rooms (LC 253)
Find the minimum number of conference rooms required to hold all meetings.
import heapq
def min_meeting_rooms(intervals: list[list[int]]) -> int:
if not intervals:
return 0
intervals.sort(key=lambda x: x[0]) # sort by start time
heap = [] # min-heap of end times (rooms, by when they free up)
for start, end in intervals:
if heap and heap[0] int:
starts = sorted(s for s, _ in intervals)
ends = sorted(e for _, e in intervals)
rooms = max_rooms = 0
j = 0
for start in starts:
if start < ends[j]:
rooms += 1
else:
j += 1 # a room freed up
max_rooms = max(max_rooms, rooms)
return max_rooms
The heap approach is O(n log n). At any point, heap size = current number of rooms in use. The two-pointer approach is cleaner in interviews.
Pattern 5: Employee Free Time (LC 759)
Find all time intervals where ALL employees are free. Merge all schedules, find gaps.
def employee_free_time(schedule: list[list[list[int]]]) -> list[list[int]]:
# Flatten all intervals
all_intervals = sorted(
[interval for employee in schedule for interval in employee],
key=lambda x: x[0]
)
# Merge overlapping intervals
merged = [all_intervals[0][:]]
for start, end in all_intervals[1:]:
if start <= merged[-1][1]:
merged[-1][1] = max(merged[-1][1], end)
else:
merged.append([start, end])
# Gaps between merged intervals are free time
free_time = []
for i in range(1, len(merged)):
free_time.append([merged[i-1][1], merged[i][0]])
return free_time
Cheat Sheet
| Problem | Sort By | Strategy |
|---|---|---|
| Merge intervals | Start time | Extend last merged interval’s end |
| Insert interval | Already sorted | 3 phases: before, merge, after |
| Min removals | End time | Greedy keep (Activity Selection) |
| Min meeting rooms | Start time | Min-heap of end times |
| Free time | Start time | Merge all, find gaps |
🏢 Asked at: Meta Interview Guide 2026: Facebook, Instagram, WhatsApp Engineering
🏢 Asked at: Apple Interview Guide 2026: iOS Systems, Hardware-Software Integration, and iCloud Architecture
🏢 Asked at: Databricks Interview Guide 2026: Spark Internals, Delta Lake, and Lakehouse Architecture
🏢 Asked at: Atlassian Interview Guide
🏢 Asked at: Coinbase Interview Guide