D'après mon commentaire à l'origine: Ceci est étroitement lié à une quantité omniprésente dans l'évaluation de la productivité académique, l'indice de Hirsh, mieux connu sous le nom d' index h . En bref , il est défini comme le nombre de publications on a de telle sorte que chacun d'entre eux a au moins h citations (le plus grand tel h ).hhh
La seule façon dont votre problème diffère est que vous seriez intéressé non seulement par le nombre de publications qui satisfont au critère, mais également par leur nombre de citations , mais c'est une modification triviale. Les données sont déjà là, l'algorithme d'origine les supprime.
Le calcul généralement mis en œuvre est assez simple et correspond à la réponse de Karolis Juodelė .
Mise à jour: selon la taille et le caractère de vos données, il peut être utile d'explorer des méthodes qui trient partiellement le tableau en filtrant les données au-dessus et en dessous d'un point pivot (quicksort me vient à l'esprit). Ensuite, selon qu'il y en a trop ou trop peu, ajustez le pivot et refaites le sous-ensemble qui le contient et ainsi de suite. Vous n'avez pas besoin d'un ordre entre les éléments supérieurs à , et certainement pas entre ceux inférieurs à cela. Ainsi, par exemple, une fois que vous avez trouvé tous les éléments supérieurs ou égaux à h 1 et qu'il y en a moins de h 1 , vous n'avez plus besoin de toucher à ce sous-ensemble, il suffit de l'ajouter. Cela convertit la récursivité inhérente au tri rapide en une récursion de queue et peut donc être réécrite sous forme de boucle.hh1h1
Mon Haskell est un peu rouillé mais cela devrait faire ce que j'ai décrit ci-dessus et semble fonctionner. J'espère que cela peut être compris dans une certaine mesure, je suis heureux de fournir des explications supplémentaires.
-- 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 []
L'idée est de collecter granted
ce que vous savez certainement participer au résultat, et de ne plus le trier. Si greater
avec des x
ajustements, nous avons de la chance, sinon nous devons essayer avec un sous-ensemble plus petit. (Le pivot x
est simplement ce qui s'est avéré être le premier élément de la sous-liste qui est actuellement considéré.) Notez que l'avantage significatif contre la prise d'éléments les plus grands un par un est que nous le faisons sur des blocs de taille moyenne et vous n'avez pas besoin de les trier davantage.r e m a i n i n g/ 2
Exemple:
Prenons votre ensemble [1,3,4,1,3,6]
.
x = 1
, granted = []
, greater = [3,4,1,3,6]
. Aïe, nous avons touché un cas pathologique lorsque le pivot est trop petit (en fait si petit qu'il smaller
est vide) dès la première étape. Heureusement, notre algo est prêt pour cela. Il se défait x
et essaie à nouveau avec greater
seul.
x = 3
, granted = []
, greater = [4,3,6]
. Ensemble, ils forment un tableau de longueur 4 mais nous n'avons que cela limité d'en bas par 3, c'est trop. Répétez greater
seul.
x = 4
, granted = []
, greater = [6]
. Cela donne un tableau de 2 éléments ≥ 4 chacun, semble que nous pourrions avoir besoin pour certains d'entre eux. Gardez cela et répétez smaller = [3]
.
x = 3
, granted = [4,6]
, greater = []
. Cela donne ensemble un tableau de 3 éléments ≥ 3 chacun, nous avons donc notre solution [3,4,6]
et nous pouvons revenir. (Notez que la permutation peut varier en fonction de l'ordre de l'entrée, mais contiendra toujours les termes les plus élevés possibles, jamais [3,3,6]
ou [3,3,4]
pour votre exemple.)
(En fait, notez que la récursivité s'est en effet effondrée en un cycle.) La complexité est légèrement meilleure que le tri rapide en raison des nombreuses comparaisons enregistrées:
n - 1
O ( logn )O ( n )
nO ( n2)
Il y a quelques comparaisons inutiles dans le code ci-dessus, comme calculer smaller
si nous en avons besoin ou non, elles peuvent être facilement supprimées. (Je pense que l'évaluation paresseuse s'en occupera cependant.)