10. Поддерживать топ-5 максимальных значений в потоке чисел
Условие задачи:
Необходимо реализовать структуру данных, которая:
принимает поток целых чисел по одному;
в любой момент времени позволяет получить пять наибольших значений среди всех уже добавленных;
не хранит весь входной поток.
Код:
interface I1<T> {
void putValue(T value);
List<T> getTopFive();
}
Спойлеры к решению
Подсказки
💡 Достаточно постоянно поддерживать только пять максимальных значений.
💡 Для этого удобно использовать
PriorityQueue как min-heap.💡 Минимальный элемент из текущего топ-5 находится в
peek().💡 Если новое число больше минимального элемента топ-5, его нужно заменить.
Решение
class IntegerTopFive implements I1<Integer> {
private static final int LIMIT = 5;
private final PriorityQueue<Integer> minHeap =
new PriorityQueue<>();
@Override
public void putValue(Integer value) {
if (minHeap.size() < LIMIT) {
minHeap.offer(value);
return;
}
if (value > minHeap.peek()) {
minHeap.poll();
minHeap.offer(value);
}
}
@Override
public List<Integer> getTopFive() {
return minHeap.stream()
.sorted(Comparator.reverseOrder())
.toList();
}
}
Пример использования:
IntegerTopFive topFive = new IntegerTopFive();
topFive.putValue(10);
topFive.putValue(5);
topFive.putValue(20);
topFive.putValue(3);
topFive.putValue(8);
topFive.putValue(25);
topFive.putValue(15);
System.out.println(topFive.getTopFive());
Результат:
[25, 20, 15, 10, 8]
PriorityQueue по умолчанию работает как минимальная куча, поэтому:
minHeap.peek()
возвращает минимальное число среди текущих пяти максимальных.
Пока элементов меньше пяти, новое значение просто добавляется:
if (minHeap.size() < LIMIT) {
minHeap.offer(value);
}
Когда пять элементов уже есть, новое число интересно только в том случае, если оно больше минимального элемента текущего топ-5:
if (value > minHeap.peek()) {
minHeap.poll();
minHeap.offer(value);
}
Таким образом, очередь никогда не содержит больше пяти элементов.
PriorityQueue сама по себе не гарантирует полный порядок элементов при обходе, поэтому для результата создаётся отсортированный список:
minHeap.stream()
.sorted(Comparator.reverseOrder())
.toList();
Для каждого нового числа сложность составляет O(log k), где k = 5, то есть фактически константное время. Память — O(k), то есть хранится не более пяти значений.
Если используется Java до версии 16:
return minHeap.stream()
.sorted(Comparator.reverseOrder())
.collect(Collectors.toList());