Вопрос: Напишите функцию, которая объединяет пересекающиеся интервалы.
Например, учитывая [(2, 6), (7, 10), (4, 6), (12, 13)], вы должны вернуть [(2, 6), (7, 10), (12, 13) )],
Например, учитывая [(1, 4), (6,9), (3, 5), (7,8)], вы должны вернуть [(1, 5), (6, 9)].
Подсказки:
- Было бы проще сортировать интервалы по времени начала,
- Вы можете использовать стек для хранения объединенных интервалов,
- Вам нужно перебирать интервалы, объединяя их, если дата начала предшествует концу последних интервалов, или нажимать новый.
Решение:
func mergingIntervals(intervals: [(Int, Int)]) -> [(Int, Int)] { // 1. guard intervals.count > 1 else { return intervals } // 2. let sortedIntervals = intervals.sorted { $0.0 < $1.0 } // 3. var result = Array(intervals[0..<1]) // 4. for interval in sortedIntervals { // 5. let top = result.last! // cannot be empty if interval.0 >= top.1 { result.append(interval) } else { result[result.count - 1] = (top.0, max(top.1, interval.1)) } } // 6. return result }
Пояснения:
1. Если интервал один и сливать нечего, вернём список.
guard intervals.count > 1 else { return intervals }
2. Отсортируем интервалы по времени начала.
let sortedIntervals = intervals.sorted { $0.0 < $1.0 }
3. Создадим результирующий массив с первым событием.
var result = Array(intervals[0..<1])
4. Теперь перебираем все отсортированные интервалы.
for interval in sortedIntervals {
5. Если текущий интервал начинается после окончания верхнего в результате, добавим его в результирующий массив. В противном случае давайте обновим последний интервал результатов последним временем окончания (максимальное текущее время окончания и время последнего результата).
let top = result.last! // cannot be empty if interval.0 >= top.1 { result.append(interval) } else { result[result.count - 1] = (top.0, max(top.1, interval.1)) }
6. В конце концов, верните все объединенные интервалы.
return result
Сложность:
- Временная сложность: сортировка всех интервалов приводит к временной сложности O (n log n),
- Пространственная сложность: как и в худшем случае, нет перекрывающихся интервалов, а пространственная сложность линейна O(n).
Тест-кейсы:
public func testMergingIntervals() { assert(mergingIntervals(intervals: [(2, 6), (7, 10), (4, 6), (12, 13)]).debugDescription == "[(2, 6), (7, 10), (12, 13)]", "mergingIntervals 1 not equal") assert(mergingIntervals(intervals: [(1, 4), (6,9), (3, 5), (7,8)]).debugDescription == "[(1, 5), (6, 9)]", "mergingIntervals 2 not equal") }
Следовать за:
Найдите минимальное количество помещений для проведения этих встреч.
Например, учитывая [(30, 75), (0, 50), (60, 150)], вы должны вернуть 2,
Например, учитывая [(1, 3), (5, 7), (2, 4), (6, 8)], вы должны вернуть 2,
Например, учитывая [(1, 3), (7, 9), (4, 6), (10, 13)], вы должны вернуть 1.
Подсказки:
- На этот раз вам нужно разделить время начала и окончания,
- Вам нужно рассчитать максимум в параллельных встречах,
- Добавляйте одну комнату, когда начинается любое собрание, и удаляйте одно помещение, когда любое собрание останавливается.
Решение:
func minRooms(meetings: [(Int, Int)]) -> Int { // 1. guard meetings.count > 1 else { return meetings.count } // 2. var starts = [Int]() var ends = [Int]() // 3. for meeting in meetings { let (start, end) = meeting starts.append(start) ends.append(end) } // 4. starts.sort() ends.sort() // 5. var maxRooms = 0 var currentRooms = 0 var indexStart = 0 var indexEnd = 0 // 6. while indexStart < starts.count { if starts[indexStart] < ends[indexEnd] { // 7. currentRooms += 1 indexStart += 1 } else { // 8. currentRooms -= 1 indexEnd += 1 } // 9. maxRooms = max(maxRooms, currentRooms) } // 10. return maxRooms }
Пояснения:
1. Если собраний меньше двух, нам нужно столько комнат, сколько у нас собраний (0 или 1).
guard meetings.count > 1 else { return meetings.count }
2. Создадим отдельные массивы для времени начала и окончания.
var starts = [Int]() var ends = [Int]()
3. Из всех встреч заполним массивы времени начала и окончания.
for meeting in meetings { let (start, end) = meeting starts.append(start) ends.append(end) }
4. Отсортируем оба временных массива.
starts.sort() ends.sort()
5. Определим некоторые переменные (максимальное количество комнат, текущее количество комнат, индекс времени начала, индекс времени окончания).
var maxRooms = 0 var currentRooms = 0 var indexStart = 0 var indexEnd = 0
6. Давайте повторять до тех пор, пока начальный индекс не будет равен или больше, чем количество начальных моментов.
while indexStart < starts.count {
7. Если текущее время начала меньше текущего времени окончания, увеличим текущее количество комнат и индекс времени начала.
if starts[indexStart] < ends[indexEnd] { currentRooms += 1 indexStart += 1
8. Если текущее время окончания больше или равно текущему времени начала, уменьшим текущее количество комнат и увеличим индекс времени окончания.
} else { currentRooms -= 1 indexEnd += 1 }
9. Сохраняйте максимальное количество комнат (предыдущее максимальное и текущее количество комнат).
maxRooms = max(maxRooms, currentRooms)
10. Вернуть максимальное количество необходимых комнат.
return maxRooms
Сложность:
- Сложность времени: сортировка всех времен начала и окончания приводит к сложности времени O (n log n),
- Сложность пространства: разделение времени начала и окончания делает сложность пространства линейной O(n).
Тест-кейсы:
public func testMinRooms() { assert(minRooms(meetings: [(30, 75), (0, 50), (60, 150)]) == 2, "minRooms 1 not equal") assert(minRooms(meetings: [(1, 3), (5, 7), (2, 4), (6, 8)]) == 2, "minRooms 2 not equal") assert(minRooms(meetings: [(1, 3), (7, 9), (4, 6), (10, 13)]) == 1, "minRooms 3 not equal") }
Следовать за:
Больше никаких уточняющих вопросов.
‹‹ Структуры данных, алгоритмы и вопросы для интервью ››
Повышение уровня кодирования
Спасибо, что являетесь частью нашего сообщества! Перед тем, как ты уйдешь:
- 👏 Хлопайте за историю и подписывайтесь на автора 👉
- 📰 Смотрите больше контента в публикации Level Up Coding
- 🔔 Подписывайтесь на нас: Twitter | ЛинкедИн | "Новостная рассылка"
🚀👉 Присоединяйтесь к коллективу талантов Level Up и найдите прекрасную работу