Не переоценивайте, насколько велик log(M)
, для большого списка длины M
. Для списка, содержащего миллиард элементов, log(M)
равно только 30. Таким образом, сортировка и выборка не такой уж неразумный метод. На самом деле сортировка массива целых чисел происходит намного быстрее благодаря сортировке списка (и массив также занимает меньше памяти), поэтому я бы сказал, что ваша лучшая (короткая) ставка (которая безопасна для коротких или пустых списков благодаря takeRight
)
val arr = s.toArray
java.util.Arrays.sort(arr)
arr.takeRight(N).toList
Есть несколько других подходов, которые можно использовать, но реализации менее просты. Вы можете использовать частичную быструю сортировку, но у вас есть те же проблемы с наихудшими сценариями, что и для быстрой сортировки (например, если ваш список уже отсортирован, наивный алгоритм может быть O(n^2)
!). Вы можете сохранить верхнюю N
в кольцевом буфере (массиве), но для этого потребуется O(log N)
бинарный поиск на каждом шаге, а также O(N/4)
скольжение элементов - хорошо, только если N
довольно мало. Более сложные методы (например, основанные на двойной поворотной быстрой сортировке) более сложны.
Поэтому я рекомендую вам попробовать сортировку массивов и посмотреть, достаточно ли это быстро.
(Конечно, ответы различаются, если вы сортируете объекты вместо чисел, но если ваше сравнение всегда можно уменьшить до числа, вы можете s.map(x => /* convert element to corresponding number*/).toArray
, а затем взять выигрышные баллы и снова просмотреть список, считая от числа, которое вам нужно взять для каждого счета, как вы находите их, это немного бухгалтерия, но не сильно замедляет все, кроме карты.)