Z mojego komentarza pierwotnie: Jest to ściśle związane z wszechobecnym ilość w akademickiego oceny produktywności, indeks Hirsh, lepiej znany jako -indexh . W skrócie jest zdefiniowany jako liczba publikacji ma się tak, że każdy z nich ma co najmniej h cytowań (największy taki h ).hhh
Twój problem różni się tylko tym, że interesowałbyś się nie tylko liczbą publikacji spełniających to kryterium, ale także liczbą ich cytowań , ale to banalna modyfikacja. Dane już tam są, oryginalny algorytm po prostu je upuszcza.
Ogólnie stosowane obliczenia są dość proste i zgadzają się z odpowiedzią Karolis Juodelė .
Aktualizacja: W zależności od wielkości i charakteru danych warto zbadać metody, które częściowo sortują tablicę, filtrując dane powyżej i poniżej punktu kluczowego (przychodzi na myśl szybkie sortowanie). Następnie w zależności od tego, czy jest za mało, czy za dużo, dostosuj oś obrotu i ponów w podzbiorze, który ją zawiera i tak dalej. Nie potrzebujesz kolejności między elementami wyższymi niż , a na pewno nie między tymi niższymi. Na przykład, gdy znajdziesz wszystkie elementy większe lub równe h 1 i jest ich mniej niż h 1 , nie musisz ponownie dotykać tego podzbioru, po prostu dodaj go. Konwertuje to rekurencję związaną z Quicksort na rekurencję ogona, a zatem może być przepisana jako pętla.hh1h1
Mój Haskell jest trochę zardzewiały, ale powinno to zrobić to, co opisałem powyżej i wydaje się działać. Mam nadzieję, że do pewnego stopnia można to zrozumieć, chętnie udzielę dalszych wyjaśnień.
-- just a utility function
merge :: [a] -> [a] -> [a]
merge [] ys = ys
merge (x:xs) ys = x : merge xs ys
-- the actual implementation
topImpl :: [Int] -> [Int] -> [Int]
topImpl [] granted = granted
topImpl (x:xs) granted
| x == (1 + lGreater + lGranted) = x : merge greater granted
| x > (1 + lGreater + lGranted) = topImpl smaller (x : merge greater granted)
| otherwise = topImpl greater granted
where smaller = [y | y <- xs, y < x]
greater = [y | y <- xs, y >= x]
lGreater = length greater
lGranted = length granted
-- starting point is: top of whole array, granted is empty
top :: [Int] -> [Int]
top arr = topImpl arr []
Chodzi o to, aby zebrać grantedto, co wiesz, na pewno będzie uczestniczyć w wyniku, a nie sortować go dalej. Jeśli greaterrazem z xpasowaniem mamy szczęście, w przeciwnym razie musimy spróbować z mniejszym podzbiorem. (Czop xjest po prostu cokolwiek stało się pierwsza pozycja w podmenu, który jest aktualnie rozpatrywana.) Należy zauważyć, że znacząca zaleta przed sobą największe elementy jeden po drugim jest to, że robimy to na blokach średniej wielkości i nie trzeba ich dalej sortować.remaining/2
Przykład:
Weźmy twój zestaw [1,3,4,1,3,6].
x = 1, granted = [], greater = [3,4,1,3,6]. Ojej, trafiliśmy na przypadek patologiczny, gdy oś jest za mała (właściwie tak mała, że smallerjest pusta) już na pierwszym etapie. Na szczęście nasze algo jest na to gotowe. Odrzuca xi próbuje ponownie greatersam.
x = 3, granted = [], greater = [4,3,6]. Razem tworzą tablicę o długości 4, ale ograniczamy ją tylko od dołu o 3, więc to za dużo. Powtórz greatersam.
x = 4, granted = [], greater = [6]. Daje to tablicę zawierającą 2 elementy ≥ 4 każdy, wydaje się, że moglibyśmy użyć trochę więcej. Zachowaj to i powtarzaj dalej smaller = [3].
x = 3, granted = [4,6], greater = []. To razem daje tablicę 3 elementów ≥ 3 każdy, więc mamy nasze rozwiązanie [3,4,6]i możemy wrócić. (Pamiętaj, że permutacja może się różnić w zależności od kolejności wprowadzania danych, ale zawsze będzie zawierać najwyższe możliwe warunki, nigdy [3,3,6]lub [3,3,4]w twoim przykładzie).
(Przy okazji zauważmy, że rekurencja rzeczywiście po prostu zapadła się w cykl.) Złożoność jest nieco lepsza niż szybkie sortowanie z powodu wielu zapisanych porównań:
n−1
O(logn)O(n)
nO(n2)
W powyższym kodzie znajduje się kilka niepotrzebnych porównań, takich jak obliczenie, smallerczy jest to potrzebne, czy nie, można je łatwo usunąć. (Myślę, że leniwa ocena to załatwi.)