J'ai un problème algorithmique.
Soit un tableau (ou un ensemble) de entiers non négatifs. Trouver l'ensemble maximal de tel que pour tout ,.
Par exemple:
- Si = [1, 3, 4, 1, 3, 6], alors peut être [3, 3, 6] ou [3, 4, 6] ou [4, 3, 6].
- Dans = [7, 5, 1, 1, 7, 4], alors est [7, 5, 7, 4].S
J'ai essayé cette fonction récursive.
function(T):
if minimum(T) >= length(T):
return T
else:
return function(T\minimum(T))
Existe-t-il un algorithme non récursif. (Je n'ai pas vérifié mon algorithme récursif, donc il pourrait avoir un défaut.)
algorithms
optimization
sets
drzbir
la source
la source
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' indexh . 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 ).h h h
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.h h1 h1
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.
L'idée est de collecterr e m a i n i n g/ 2
granted
ce que vous savez certainement participer au résultat, et de ne plus le trier. Sigreater
avec desx
ajustements, nous avons de la chance, sinon nous devons essayer avec un sous-ensemble plus petit. (Le pivotx
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.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'ilsmaller
est vide) dès la première étape. Heureusement, notre algo est prêt pour cela. Il se défaitx
et essaie à nouveau avecgreater
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étezgreater
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étezsmaller = [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:
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.)la source
Il n'y a rien de mal avec votre algorithme, et bien sûr la plupart des algorithmes récursifs peuvent être convertis en boucles, voici une version en boucle de votre code récursif:
la source
Tout algorithme récursif peut être réécrit pour utiliser l'itération. Après tout, une machine de Turing ne sait rien de la récursivité mais peut implémenter n'importe quel algorithme. En principe, vous pouvez réécrire votre fonction récursive en écrivant votre propre code de manipulation de pile pour vous souvenir des valeurs des paramètres de la fonction et de toutes les variables locales qu'elle pourrait avoir. Dans ce cas particulier, votre fonction est récursive de queue (une fois qu'un appel récursif revient, la chose qui l'a appelée revient immédiatement aussi), vous n'avez donc même pas besoin de maintenir la pile.
la source
Utilisez un min-tas pour effectuer un tri partiel, car vous n'avez pas besoin de trier l'ensemble du tableau.
Continuez à faire sauter les éléments avec avidité jusqu'à ce que vous dépassiez le seuil indiqué.
la source