Znalezienie k-tego najmniejszego elementu z danej sekwencji tylko z czasem O (k) pamięci O (k)


11

Załóżmy, że odczytujemy ciąg n liczb, jeden po drugim. Jak znaleźć k najmniejszy element za pomocą pamięci komórkowej O(k) oraz w czasie liniowym ( O(n) ). Myślę, że powinniśmy zapisać pierwsze k wyrażeń w sekwencji, a kiedy otrzymamy k+1 -ty termin, usuń go, który z pewnością nie może być k -tym najmniejszym elementem, a następnie zapisz k+1 -ty termin. Powinniśmy więc mieć wskaźnik, który pokazuje ten bezużyteczny termin na każdym etapie, a wskaźnik ten powinien być aktualizowany na każdym kroku szybko. Zacząłem od „max”; ale nie można szybko zaktualizować; Oznacza to, że jeśli weźmiemy pod uwagę max, to przy pierwszym usuwaniu pomijamy maksimum i powinniśmy szukać maksimum w O(k) i jego przyczynie (n−k)×O(k) czas, że nie jest on liniowy. Może powinniśmy bardziej inteligentnie zapisać pierwsze k warunków sekwencji.

Jak rozwiązać ten problem?


1
Czy jesteś zainteresowany algorytmem online, czy zrobiłby to jakiś algorytm?
— Yuval Filmus

Jeśli k=θ(n) , możesz to zrobić za pomocą algorytmu statystyki zamówień. Jeśli k=o(n) , możesz to zrobić Pamięć O(k) i czas O(nlog⁡k) przy użyciu dowolnego drzewa o zrównoważonej wysokości.
— Shreesh

To się nazywa problem selekcji en.wikipedia.org/wiki/Selection_algorithm
— xavierm02

Istnieją algorytmy czasu lokalnego liniowe, które można wyszukiwać w Google, ale są one nieco skomplikowane.
— Yuval Filmus

@ xavierm02 to nie problem identyczny. Ponieważ istnieje ograniczenie limitu pamięci.
— Shahab_HK

Odpowiedzi:


16

Utwórz bufor o rozmiarze . Wczytaj 2 k elementów z tablicy. Użyj algorytmu wyboru czasu liniowego, aby podzielić bufor, tak aby k najmniejszych elementów było pierwsze; zajmuje to czas O ( k ) . Teraz wczytaj kolejne k elementów z tablicy do bufora, zastępując k największych elementów w buforze, podziel bufor jak poprzednio i powtórz.2k2kkO(k)kk

To zajmuje czas i O ( k ) przestrzeń.O(k∗n/k)=O(n)O(k)


+1, to pasuje do zadanych asymptotyków. To powiedziawszy, nie sądzę, że jest to szybsze niż wykonanie pojedynczego algorytmu selekcji w czasie liniowym ... z wyjątkiem sytuacji, gdy jest małą stałą, zapewnia to interesującą perspektywę. Na przykład dla k = 1 ten algorytm tworzy funkcję. kk=1min
— orlp

1
Czasami algorytm wyboru czasu liniowego zajmuje zbyt dużo miejsca. Na przykład nie nadaje się do użycia w kontekście przesyłania strumieniowego lub gdy tablica wejściowa jest niezmienna.
— jbapple

To są ważne punkty.
— orlp

3

O(k)O(nlog⁡k)kO(k)O(log⁡k)O(k+nlog⁡k)O(nlog⁡k)

O(log⁡n)O(n)kk

O(log⁡n)O(k)O(log⁡n)264log⁡264=64kn


O(n×log⁡min(k,n−k))

@ xavierm02 = . Dowód: najgorszym przypadkiem dla jest . Najgorszy przypadek dla to . Są takie same w ramach stałego współczynnika, a zatem = . O(min(k,n−k))O(k)knmin(k,n−k)n2O(min(k,n−k))O(k)
— orlp

@ xavierm02 To powiedziawszy, to wciąż niezłe przyspieszenie :)
— orlp

un,k=k to ale to nie . Załóżmy, że tak. Potem jest trochę i trochę tak że dla każdego mamy , co jest wyraźnie fałszywe (ponieważ możemy przyjąć Więc . O(k)O(min(k,n−k))CMM≤k≤nk≤C(n−k)n=k→+∞).O(min(k,n−k))⊊O(k)
— xavierm02

@ xavierm02 Nie znam twojej notacji . Aby być uczciwym, ogólnie nie jestem zaznajomiony z wielowymiarową notacją big- , szczególnie biorąc pod uwagę, że wymiary nie są ze sobą niezwiązane. un,kOn,k
— orlp
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.