Подтвердить что ты не робот

FInd перекрывающиеся встречи в O (n) времени?

Недавно я задал этот вопрос в интервью. Несмотря на то, что я смог найти решение O (n²), интервьюер был одержим решением O (n). Я также проверил несколько других решений O (n logn), которые я понял, но O (n) решение по-прежнему не является моей чашкой чая, которая предполагает встречи, отсортированные по времени начала.

Кто-нибудь может это объяснить?

Заявление о проблемах: Вам назначены n назначений. Каждое назначение содержит время начала и время окончания. Вы должны эффективно перенастраивать все конфликтующие встречи.

Лицо: 1,2, 3, 4, 5
Начало приложения: 2, 4, 29, 10, 22
App End: 5, 7, 34, 11, 36

Ответ: 2x1 5x3

Алгоритм O (n logn): отдельный начальный и конечный пункт следующим образом:

2s, 4s, 29s, 10s, 22s, 5e, 7e, 34e, 11e, 36e

затем отсортировать все эти точки (для простоты пусть каждая точка уникальна):

2s, 4s, 5e, 7e, 10s, 11e, 22s, 29s, 34e, 36e

Если у нас есть последовательные пуски без концов, то он перекрывается: 2s, 4s смежны, поэтому перекрытие есть

Мы будем держать счетчик "s", и каждый раз, когда мы сталкиваемся с ним, будет +1, а когда встречается e, мы уменьшаем счет на 1.

4b9b3361

Ответ 1

Общее решение этой проблемы невозможно в O (n).

Как минимум вам нужно сортировать по времени начала встречи, для чего требуется O (n log n).

Существует решение O (n) , если список уже отсортирован. Алгоритм в основном включает проверку того, перекрывается ли следующая встреча с предыдущими. Для этого есть немного тонкости, так как вам действительно нужны два указателя в списке, когда вы проходите через него:

  • Текущее назначение будет проверено
  • Назначение с самым последним временем окончания времени (которое может не совпадать с предыдущим назначением)

O (n) решения для несортированного случая могут существовать только в том случае, если у вас есть другие ограничения, например. фиксированное количество временных интервалов приема. Если это так, то вы можете использовать HashSets, чтобы определить, какая встреча (-ы) покрывает каждый временной интервал, алгоритм примерно следующим образом:

  • Создайте HashSet для каждого временного интервала - O (1), так как число временных интервалов является фиксированной константой
  • Для каждой встречи сохраните свой идентификационный номер в HashSets слота (ов), который он охватывает - O (n), поскольку обновление постоянного количества временных интервалов равно O (1) для каждой встречи
  • Запуск через слоты, проверка на перекрытия - O (1) (или O (n), если вы хотите перебирать перекрывающиеся встречи, чтобы вернуть их в качестве результатов)

Ответ 2

Предполагая, что у вас есть ограничение на время начала и окончания и на разрешение, на котором вы выполняете планирование, похоже, было бы довольно легко превратить каждую встречу в растровое изображение того времени, когда оно делает/не использует, затем сделайте сортировку (например, сортировку ведра) в используемых слотах. Поскольку оба из них линейны, результат должен быть линейным (хотя, если я правильно думаю, он должен быть линейным по количеству временных интервалов, а не количеству назначений).

По крайней мере, если бы я задал этот вопрос как вопрос для интервью, главное, на что я надеюсь, - это кандидат на вопрос об этих ограничениях (т.е. разрешены ли эти ограничения). Учитывая, насколько нереально планировать встречи на 1000 лет или планировать с точностью до минуты (не говоря уже о наносекунде), они кажутся мне разумными ограничениями, но вы должны спросить, прежде чем принимать их.

Ответ 3

Наивный подход может заключаться в построении двух параллельных деревьев, упорядоченных по начальной точке, и одного упорядоченного по конечной точке каждого интервала. Это позволяет отбросить половину каждого дерева в O (log n), но результаты должны быть объединены, требуя O (n) времени. Это дает нам запросы в O (n + log n) = O (n).

Ответ 4

Это лучшее, что я могу придумать, в ужасном псевдокоде. Я попытался максимально уменьшить проблему. Это меньше, чем On ^ 2 (я думаю).

Обратите внимание, что вывод в конце не будет показывать каждую встречу, что данная встреча будет конфликтовать с этой конкретной выходной строкой... но в какой-то момент отображается каждый конфликт.

Также обратите внимание, что я переименовал встречи численно в порядке времени начала.

output would be something like the following:

Appointment 1 conflicts with 2
Appointment 2 conflicts with
Appointment 3 conflicts with
Appointment 4 conflicts with 5
Appointment 5 conflicts with

appt{1},appt{2},appt{3} ,appt{4} ,appt{5}
  2      4       10       22      29
  5      7       11       36      34

псевдокод

list=(1,2,3,4,5)
for (i=1,i<=5,i++)
    list.shift()   **removes first element
    appt{i}.conflictswith()=list

for (i=1,i<=n,i++)
{   number=n
    done=false
    while(done=false)
        {if (number>i)
            {if (appt(i).endtime() < appt(number).startime())
                {appt{i}.conflictswith().pop()}
             else
                {done=true}
             number--
             }
        else
            {done=true}
        }
}
for (i=1,i<=n,i++)
    print "Appointment ",i," conflicts with:",appt{i}.conflictswith()  

Ответ 5

Я наткнулся на структуру данных, которая называется деревом Interval, с помощью которой мы можем найти интервалы менее чем за время O (n log (n)), в зависимости от предоставленных данных