Files
codetutor/backend/data/patterns/intervals.yaml

278 lines
7.9 KiB
YAML

name: Overlapping Intervals
slug: intervals
difficulty_level: 2
pattern_type: technique
display_order: 13
description: >
Process and manipulate intervals (ranges) that may share common regions.
The key insight is that sorting intervals by start time allows efficient
detection and handling of overlaps through a single linear pass.
when_to_use: |
- Merging overlapping intervals
- Inserting an interval into a sorted list
- Finding gaps between intervals
- Meeting room scheduling
- Finding interval intersections
metaphor: |
Imagine scheduling meeting rooms. Each meeting is an interval of time. When
two meetings overlap, you need either two rooms or to merge them into one
longer booking. By sorting meetings by start time, you can easily spot
overlaps—if the next meeting starts before the current one ends, they overlap.
Another analogy: merging overlapping highlighter marks on a page. Sort them
left to right, and if one mark starts before the previous ends, combine them
into one continuous highlight.
core_concept: |
The **interval pattern** relies on sorting intervals by start time. Once sorted,
overlapping detection becomes simple:
**Two intervals [a, b] and [c, d] overlap if c <= b** (assuming a <= c after sorting)
Key operations:
1. **Merge**: Extend the current interval's end to include overlapping intervals
2. **Insert**: Find where the new interval overlaps and merge as needed
3. **Count overlaps**: Track how many intervals are "active" at any point
For problems needing simultaneous tracking (like minimum meeting rooms), use
a **sweep line** approach: sort all start and end points together, then sweep
through counting active intervals.
visualization: |
**Merging overlapping intervals:**
```
Input: [[1,3], [2,6], [8,10], [15,18]]
(sorted by start)
Process [1,3]: result = [[1,3]]
Process [2,6]: 2 <= 3? Yes, overlap!
Merge: [1, max(3,6)] = [1,6]
result = [[1,6]]
Process [8,10]: 8 <= 6? No, no overlap
result = [[1,6], [8,10]]
Process [15,18]: 15 <= 10? No, no overlap
result = [[1,6], [8,10], [15,18]]
```
**Visualized on number line:**
```
Before: [1---3]
[2------6]
[8--10]
[15--18]
After: [1--------6] [8--10] [15--18]
```
**Meeting rooms (sweep line):**
```
Meetings: [[0,30], [5,10], [15,20]]
Events (sorted):
time=0: +1 (start) active=1
time=5: +1 (start) active=2 ← max
time=10: -1 (end) active=1
time=15: +1 (start) active=2 ← max
time=20: -1 (end) active=1
time=30: -1 (end) active=0
Max concurrent = 2 → need 2 meeting rooms
```
code_template: |
def merge_intervals(intervals: list[list[int]]) -> list[list[int]]:
"""Merge overlapping intervals."""
if not intervals:
return []
# Sort by start time
intervals.sort(key=lambda x: x[0])
result = [intervals[0]]
for start, end in intervals[1:]:
last_end = result[-1][1]
if start <= last_end: # Overlap
result[-1][1] = max(last_end, end) # Extend
else:
result.append([start, end])
return result
def insert_interval(intervals: list[list[int]],
new: list[int]) -> list[list[int]]:
"""Insert and merge a new interval into sorted list."""
result = []
i = 0
n = len(intervals)
# Add all intervals before new interval
while i < n and intervals[i][1] < new[0]:
result.append(intervals[i])
i += 1
# Merge overlapping intervals with new
while i < n and intervals[i][0] <= new[1]:
new[0] = min(new[0], intervals[i][0])
new[1] = max(new[1], intervals[i][1])
i += 1
result.append(new)
# Add remaining intervals
while i < n:
result.append(intervals[i])
i += 1
return result
def min_meeting_rooms(intervals: list[list[int]]) -> int:
"""Find minimum meeting rooms needed (sweep line)."""
events = []
for start, end in intervals:
events.append((start, 1)) # +1 for start
events.append((end, -1)) # -1 for end
# Sort by time, with ends before starts at same time
events.sort(key=lambda x: (x[0], x[1]))
max_rooms = 0
current_rooms = 0
for _, delta in events:
current_rooms += delta
max_rooms = max(max_rooms, current_rooms)
return max_rooms
def interval_intersection(A: list[list[int]],
B: list[list[int]]) -> list[list[int]]:
"""Find intersection of two sorted interval lists."""
result = []
i = j = 0
while i < len(A) and j < len(B):
# Find overlap
start = max(A[i][0], B[j][0])
end = min(A[i][1], B[j][1])
if start <= end:
result.append([start, end])
# Advance the interval that ends first
if A[i][1] < B[j][1]:
i += 1
else:
j += 1
return result
def can_attend_all(intervals: list[list[int]]) -> bool:
"""Check if a person can attend all meetings."""
intervals.sort(key=lambda x: x[0])
for i in range(1, len(intervals)):
if intervals[i][0] < intervals[i-1][1]:
return False # Overlap found
return True
recognition_signals:
- "intervals"
- "merge"
- "overlapping"
- "meeting rooms"
- "schedule"
- "time slots"
- "range"
- "insert interval"
- "non-overlapping"
- "intersection"
common_mistakes:
- title: Not sorting first
description: |
Trying to process unsorted intervals leads to incorrect results because
overlaps aren't detected properly.
fix: |
Always sort intervals by start time before processing:
```python
intervals.sort(key=lambda x: x[0])
```
- title: Wrong overlap condition
description: |
Using `start < last_end` instead of `start <= last_end` misses adjacent
intervals that should be merged (like [1,2] and [2,3]).
fix: |
Use `<=` for touching intervals, `<` for strict overlap only. Check problem
requirements for whether touching counts as overlapping.
- title: Not updating end correctly when merging
description: |
Setting `end = new_end` instead of `end = max(old_end, new_end)` fails when
a smaller interval is contained within a larger one.
fix: |
Always take the maximum:
```python
result[-1][1] = max(result[-1][1], end)
```
- title: Off-by-one with closed vs open intervals
description: |
Confusion about whether interval endpoints are inclusive `[a, b]` or
exclusive `[a, b)` causes incorrect overlap detection.
fix: |
Clarify the convention from the problem. Most problems use closed intervals
where both endpoints are included.
variations:
- name: Merge intervals
description: |
Combine all overlapping intervals into non-overlapping intervals.
example: "Merge Intervals"
- name: Insert interval
description: |
Insert a new interval into a sorted list, merging with any overlapping
intervals.
example: "Insert Interval"
- name: Meeting rooms
description: |
Find minimum resources needed for concurrent intervals using sweep line
or min-heap.
example: "Meeting Rooms II, Car Pooling"
- name: Interval intersection
description: |
Find common regions between two lists of intervals using two pointers.
example: "Interval List Intersections"
- name: Non-overlapping intervals
description: |
Find minimum removals to make all intervals non-overlapping. Greedy
approach: keep intervals that end earliest.
example: "Non-overlapping Intervals, Erase Overlap Intervals"
related_patterns:
- greedy
- two-pointers
prerequisite_patterns: []