Метод точек

В этом уроке ты
  • Решишь задачу с собеседования в BigTech.
  • Освоишь “метод точек” для решения задач.
Пример задачи с собеседования

Представь, что ты заходишь на собеседование. Интервьюер уже готов и начинает озвучивать условие задачи…

Условие

Дан массив отрезков segments, где segments[i] содержит отрезок бронирования комнаты для переговоров: [начало бронирования, конец бронирования].

Нужно вернуть минимальное число переговорных комнат, которые понадобятся, чтобы все встречи могли состояться.

Пример 1
Ввод: segments = [[3,5],[2,5],[1,3],[6,7]]
Вывод: 2
Объяснение: в промежутке от 2 до 5 одновременно нужны 2 переговорные комнаты.

В момент времени 3 - сначала была освобождена комната, а потом сразу занята.

Пример 2
Ввод: segments = [[3,4],[1,100],[2,100]]
Вывод: 3
Идея решения
  1. Преобразуем каждый отрезок [start, end] в две точки:
    1. [start, +1] – сигнал, что нужна дополнительная комната
    2. [end, -1] – сигнал, что комната освобождается
  2. Сортируем все точки по их значению (при равных значениях первыми идут точки с -1).
  3. Проходим по отсортированному массиву, используя счётчик:
    1. При встрече +1 увеличиваем счётчик (занимаем комнату)
    2. При встрече -1 уменьшаем счётчик (освобождаем комнату)
  4. Максимальное значение счётчика во время прохода и будет ответом.

Например, при segments = [[3,5],[2,5],[1,3],[6,7]] в ходе преобразования в массив точек и сортировки получим массив:  

Идя по нему с учётом +1 и -1, мы найдём максимальное значение счётчика — это и есть количество необходимых комнат.

Код
public class Solution
{
    public static int CountMeetingRooms(List<List<int>> segments)
    {
        List<List<int>> points = new List<List<int>>();
        foreach (var seg in segments)
        {
            // Точка начала отрезка, +1 - нужна ещё одна комната
            points.Add(new List<int> { seg[0], +1 });
            // Точка конца отрезка, -1 - комната освобождается
            points.Add(new List<int> { seg[1], -1 });
        }

        // При равных значениях точки с -1 идут первыми
        points.Sort((a, b) => a[0] == b[0] ? a[1].CompareTo(b[1]) : a[0].CompareTo(b[0]));

        int maxRooms = 0;
        int currRooms = 0;
        foreach (var point in points)
        {
            currRooms += point[1];
            maxRooms = Math.Max(maxRooms, currRooms);
        }
        return maxRooms;
    }
}
Оценка сложности
  • Время: O(n*log(n)), где n – размер массива segments. Основная часть времени уходит на сортировку.
  • Память: O(n). Дополнительная память расходуется под массив точек и сортировку.
Метод точек

“Метод точек” предполагает, что мы превращаем каждый отрезок в набор точек начала и конца и затем работаем с ними в одном общем массиве, предварительно отсортировав.

Что дальше

Чем больше тренируешься, тем лучше усваивается материал, поэтому скорее переходи к практическим задачам. Удачи в решении!