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

Подготовьте массив в линейном времени, чтобы найти k наименьших элементов в O (k)

Это интересный вопрос, который я нашел в Интернете. Если массив содержит числа n (без информации о них), мы должны предварительно обработать массив в линейном времени, чтобы мы могли вернуть наименьшие элементы k в O(k), когда нам дано число 1 <= k <= n

Я обсуждал эту проблему с некоторыми друзьями, но никто не мог найти решение; любая помощь будет оценена!

4b9b3361

Ответ 1

Для этапа предварительной обработки мы будем использовать выбор на основе разделов несколько раз в одном наборе данных.

Найдите n/2-е число с алгоритмом. Теперь набор данных разбит на две половины, нижнюю и верхнюю. В нижней половине снова найдите среднюю точку. На нижнем разделе делают то же самое и так далее... В целом это O (n) + O (n/2) + O (n/4) +... = O (n).

Теперь, когда вам нужно вернуть k наименьших элементов, найдите ближайший x < k, где x - граница раздела. Все под ним может быть возвращено, а из следующего раздела вы должны вернуть числа k - x. Поскольку следующий размер раздела равен O (k), запуск другого алгоритма выделения для k-x-го числа вернет остальные.

Ответ 2

Мы можем найти медиану списка и разбиение вокруг него в линейном времени.

Затем мы можем использовать следующий алгоритм: поддерживать буфер размером 2k.

Каждый раз, когда буфер заполняется, мы находим медианную и разделяемую область, сохраняя только самые нижние элементы k.
Для этого требуются шаги n/k find-median-and-partition, каждый из которых принимает O(k) время с традиционным quickselect. для этого подхода требуется только время O(n).

Дополнительно, если вам нужен отсортированный вывод. Что добавляет дополнительное время O(k log k). В общем, для этого подхода требуется только время O(n + k log k) и O(k).