← все задачи
Python · задача 5 из 10
Слить пересекающиеся интервалы
Средний
15–20 минут
сортировкаинвариантыкраевые случаи
Условие
Дан список интервалов — например, занятых слотов календаря. Слейте пересекающиеся и верните минимальный набор непересекающихся интервалов, отсортированный по началу.
Что требуется
- Интервалы приходят в произвольном порядке
- Соприкасающиеся интервалы (конец одного равен началу другого) считаются смежными и сливаются
- Пустой вход — пустой выход
Пример
merge([(1, 3), (2, 6), (8, 10), (15, 18)]) # [(1, 6), (8, 10), (15, 18)] merge([(1, 4), (4, 5)]) # [(1, 5)] -> соприкасаются, значит сливаем
Сначала уточните
Вопросы до кода — половина оценки. Молча начать печатать хуже, чем задать два вопроса.
- Границы включительные или полуинтервал [start, end)? От этого зависит, сливать ли (1,4) и (4,5)
- Может ли start быть больше end — данные заранее валидны?
- Что на выходе: кортежи, списки, объекты? Нужен ли исходный список нетронутым?
Показать решение Скрыть решение
Решение
def merge(intervals):
if not intervals:
return []
# сортируем по началу: после этого достаточно смотреть только на последний слитый
ordered = sorted(intervals, key=lambda interval: interval[0])
merged = [tuple(ordered[0])]
for start, end in ordered[1:]:
last_start, last_end = merged[-1]
if start <= last_end: # пересекаются или соприкасаются
merged[-1] = (last_start, max(last_end, end))
else:
merged.append((start, end))
return merged
Почему так
Почему всё начинается с сортировки
- После сортировки по началу возникает инвариант: новый интервал может пересечься только с последним слитым
- Без него пришлось бы сравнивать каждый с каждым — O(n²) вместо O(n log n)
- Проговорить инвариант вслух важнее, чем написать код: именно это интервьюер и слушает
Почему max(last_end, end)
- Интервал может целиком лежать внутри предыдущего: (1, 10) и (2, 3) — конец брать нельзя, иначе результат сожмётся до (1, 3)
- Это самый частый баг в этой задаче, и пример с вложенным интервалом обычно дают именно для проверки
- Пример (1,10),(2,3) стоит проговорить самому до того, как его дадут
Почему start <= last_end, а не <
- Строгое неравенство оставит (1,4) и (4,5) отдельными интервалами
- Правильный ответ зависит от того, включительные границы или нет, — поэтому это первый вопрос интервьюеру
- Любой вариант принимается, если вы объяснили выбор; молчаливое допущение — нет
Что спросят дальше
- Спросят обратную задачу: найти свободные окна между занятыми слотами
- Спросят про потоковый вариант: интервалы приходят по одному и уже отсортированы — тогда сортировка не нужна вовсе
- В календарных задачах дальше идут часовые пояса — будьте готовы, что datetime с tz всплывёт
Следующая задача
Декоратор retry с экспоненциальной паузой — Самая частая задача на декораторы: проверяют и синтаксис, и понимание, что повторять можно не всё.