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ć granted
to, co wiesz, na pewno będzie uczestniczyć w wyniku, a nie sortować go dalej. Jeśli greater
razem z x
pasowaniem mamy szczęście, w przeciwnym razie musimy spróbować z mniejszym podzbiorem. (Czop x
jest 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 smaller
jest pusta) już na pierwszym etapie. Na szczęście nasze algo jest na to gotowe. Odrzuca x
i próbuje ponownie greater
sam.
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 greater
sam.
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, smaller
czy jest to potrzebne, czy nie, można je łatwo usunąć. (Myślę, że leniwa ocena to załatwi.)