Подготовьте массив в линейном времени, чтобы найти k наименьших элементов в O (k)
Это интересный вопрос, который я нашел в Интернете. Если массив содержит числа n
(без информации о них), мы должны предварительно обработать массив в линейном времени, чтобы мы могли вернуть наименьшие элементы k
в O(k)
, когда нам дано число 1 <= k <= n
Я обсуждал эту проблему с некоторыми друзьями, но никто не мог найти решение; любая помощь будет оценена!
Ответы
Ответ 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)
.