Намиране на най-добрите K елементи в Java масив

1. Общ преглед

В този урок ще приложим различни решения на проблема с намирането на k -големите елементи в масив с Java. За да опишем сложността на времето, ще използваме нотация Big-O.

2. Решение Brute-Force

Решението за груба сила на този проблем е да се прегледа през дадения масив k пъти . Във всяка итерация ще намерим най-голямата стойност . След това ще премахнем тази стойност от масива и ще я поставим в изходния списък:

public List findTopK(List input, int k) { List array = new ArrayList(input); List topKList = new ArrayList(); for (int i = 0; i < k; i++) { int maxIndex = 0; for (int j = 1; j  array.get(maxIndex)) { maxIndex = j; } } topKList.add(array.remove(maxIndex)); } return topKList; }

Ако приемем, че n е размерът на дадения масив, сложността във времето на това решение е O (n * k) . Освен това това е най-неефективното решение.

3. Подход на Java Collections

Съществуват обаче по-ефективни решения на този проблем. В този раздел ще обясним два от тях с помощта на Java Collections.

3.1. TreeSet

TreeSet има структура на данните Red-Black Tree като гръбначен стълб. В резултат на това поставянето на стойност към този набор струва O (log n) . TreeSet е сортирана колекция. Следователно можем да поставим всички стойности в TreeSet и да извлечем първите k от тях:

public List findTopK(List input, int k) { Set sortedSet = new TreeSet(Comparator.reverseOrder()); sortedSet.addAll(input); return sortedSet.stream().limit(k).collect(Collectors.toList()); }

Най сложността време на това решение е O (N * дневник н) . Преди всичко това се предполага, че е по-ефективно от подхода на груба сила, ако k ≥ log n .

Важно е да запомните, че TreeSet не съдържа дубликати. В резултат на това решението работи само за входен масив с различни стойности.

3.2. PriorityQueue

PriorityQueue е структура от данни на купчина в Java. С негова помощ можем да постигнем O (N * дневник к) разтвор . Освен това това ще бъде по-бързо решение от предишното. Поради посочения проблем, k винаги е по-малък от размера на масива. Така че, това означава, че O (n * log k) ≤ O (n * log n).

Алгоритъмът се повтаря веднъж през дадения масив . При всяка итерация ще добавяме нов елемент към купчината. Също така ще запазим размера на купчината по-малък или равен на k . Така че, ще трябва да премахнем допълнителни елементи от купчината и да добавим нови. В резултат на това, след итерация през масива, купчината ще съдържа k -големите стойности:

public List findTopK(List input, int k) { PriorityQueue maxHeap = new PriorityQueue(); input.forEach(number -> { maxHeap.add(number); if (maxHeap.size() > k) { maxHeap.poll(); } }); List topKList = new ArrayList(maxHeap); Collections.reverse(topKList); return topKList; }

4. Алгоритъм за подбор

Има много подходи за решаване на дадения проблем. И въпреки че това е извън обхвата на този урок, използването на подхода на алгоритъма за избор ще бъде най-добрият, защото дава линейна времева сложност.

5. Заключение

В този урок описахме няколко решения за намиране на k -големите елементи в масив.

Както обикновено, примерният код е достъпен в GitHub.