Je veux écrire une fonction qui prend un tableau de lettres comme argument et un certain nombre de ces lettres à sélectionner.
Supposons que vous fournissiez un tableau de 8 lettres et que vous souhaitiez en sélectionner 3. Ensuite, vous devriez obtenir:
8! / ((8 - 3)! * 3!) = 56
Tableaux (ou mots) en retour composés de 3 lettres chacun.
Réponses:
Art of Computer Programming Volume 4: Fascicle 3 en a une tonne qui pourrait mieux s'adapter à votre situation particulière que celle que je décris.
Codes gris
Un problème que vous rencontrerez est bien sûr la mémoire et assez rapidement, vous aurez des problèmes avec 20 éléments dans votre ensemble - 20 C 3 = 1140. Et si vous voulez parcourir l'ensembles, il est préférable d'utiliser un gris modifié algorithme de code afin que vous ne les gardiez pas tous en mémoire. Ceux-ci génèrent la combinaison suivante de la précédente et évitent les répétitions. Il y en a beaucoup pour différentes utilisations. Voulons-nous maximiser les différences entre les combinaisons successives? minimiser? etc.
Certains des articles originaux décrivant les codes gris:
Voici quelques autres articles couvrant le sujet:
Twiddle de Chase (algorithme)
Phillip J Chase, ` Algorithm 382: Combinations of M out of N Objects '(1970)
L'algorithme en C ...
Index des combinaisons dans l'ordre lexicographique (algorithme de boucles 515)
Vous pouvez également référencer une combinaison par son index (dans l'ordre lexicographique). En réalisant que l'indice devrait être une certaine quantité de changement de droite à gauche en fonction de l'indice, nous pouvons construire quelque chose qui devrait récupérer une combinaison.
Donc, nous avons un ensemble {1,2,3,4,5,6} ... et nous voulons trois éléments. Disons que {1,2,3} nous pouvons dire que la différence entre les éléments est un et dans l'ordre et minime. {1, 2, 4} a un changement et est lexicographiquement numéro 2. Ainsi, le nombre de "changements" en dernier lieu explique un changement dans l'ordre lexicographique. La deuxième place, avec un changement {1,3,4} a un changement mais représente plus de changement car il est à la deuxième place (proportionnel au nombre d'éléments dans l'ensemble d'origine).
La méthode que j'ai décrite est une déconstruction, comme il semble, de l'ensemble à l'index, nous devons faire l'inverse - ce qui est beaucoup plus délicat. C'est ainsi que Buckles résout le problème. J'ai écrit du C pour les calculer , avec des changements mineurs - j'ai utilisé l'index des ensembles plutôt qu'une plage de nombres pour représenter l'ensemble, donc nous travaillons toujours de 0 à n. Remarque:
Index des combinaisons dans l'ordre lexicographique (McCaffrey)
Il y a une autre façon : son concept est plus facile à saisir et à programmer mais il est sans les optimisations de Buckles. Heureusement, il ne produit pas non plus de combinaisons en double:
L'ensemble qui maximise , où .
Pour un exemple:
27 = C(6,4) + C(5,3) + C(2,2) + C(1,1)
. Donc, la 27e combinaison lexicographique de quatre choses est: {1,2,5,6}, ce sont les index de tout ensemble que vous voulez regarder. Exemple ci-dessous (OCaml), nécessite unechoose
fonction, laissé au lecteur:Un itérateur de combinaisons petites et simples
Les deux algorithmes suivants sont fournis à des fins didactiques. Ils implémentent un itérateur et (plus généralement) des combinaisons globales de dossiers. Ils sont aussi rapides que possible, ayant la complexité O ( n C k ). La consommation de mémoire est liée par
k
.Nous commencerons par l'itérateur, qui appellera une fonction fournie par l'utilisateur pour chaque combinaison
Une version plus générale appellera la fonction fournie par l'utilisateur avec la variable d'état, à partir de l'état initial. Étant donné que nous devons passer l'état entre différents états, nous n'utiliserons pas la boucle for, mais à la place, utilisez la récursivité,
la source
En C #:
Usage:
Résultat:
la source
var result = new[] { 1, 2, 3, 4, 5 }.Combinations(3);
Solution java courte:
Le résultat sera
la source
Puis-je présenter ma solution Python récursive à ce problème?
Exemple d'utilisation:
Je l'aime pour sa simplicité.
la source
len(tuple(itertools.combinations('abcdefgh',3)))
réalisera la même chose en Python avec moins de code.for i in xrange(len(elements) - length + 1):
? Peu importe en python car sortir de l'index de tranche est géré avec élégance mais c'est l'algorithme correct.Disons que votre tableau de lettres ressemble à ceci: "ABCDEFGH". Vous disposez de trois indices (i, j, k) indiquant quelles lettres vous allez utiliser pour le mot courant, vous commencez par:
D'abord, vous faites varier k, donc la prochaine étape ressemble à ceci:
Si vous avez atteint la fin, continuez et faites varier j puis k à nouveau.
Une fois que vous avez atteint G, vous commencez également à varier i.
Écrit dans le code cela ressemble à ça
la source
L'algorithme récursif suivant sélectionne toutes les combinaisons d'éléments k dans un ensemble ordonné:
i
de votre combinaisoni
avec chacune des combinaisons d'k-1
éléments choisis récursivement dans l'ensemble d'éléments plus grands quei
.Répétez ce qui précède pour chacun
i
dans l'ensemble.Il est essentiel que vous choisissiez le reste des éléments comme étant plus grand que
i
, pour éviter la répétition. De cette façon, [3,5] sera sélectionné une seule fois, comme [3] combiné avec [5], au lieu de deux (la condition élimine [5] + [3]). Sans cette condition, vous obtenez des variations au lieu de combinaisons.la source
En C ++, la routine suivante produira toutes les combinaisons de distance de longueur (première, k) entre la plage [première, dernière):
Il peut être utilisé comme ceci:
Cela imprimera ce qui suit:
la source
being
etbegin
avecs.begin()
, etend
avecs.end()
. Le code suit de près l'next_permutation
algorithme de STL , décrit ici plus en détail.J'ai trouvé ce fil utile et j'ai pensé ajouter une solution Javascript que vous pouvez insérer dans Firebug. Selon votre moteur JS, cela peut prendre un peu de temps si la chaîne de départ est grande.
La sortie doit être la suivante:
la source
la source
Petit exemple en Python:
Pour explication, la méthode récursive est décrite avec l'exemple suivant:
Exemple: ABCDE
Toutes les combinaisons de 3 seraient:
la source
Algorithme récursif simple dans Haskell
Nous définissons d'abord le cas particulier, c'est-à-dire la sélection de zéro élément. Il produit un seul résultat, qui est une liste vide (c'est-à-dire une liste qui contient une liste vide).
Pour n> 0,
x
passe par chaque élément de la liste etxs
est chaque élément aprèsx
.rest
sélectionne desn - 1
éléments àxs
partir d'un appel récursif àcombinations
. Le résultat final de la fonction est une liste où chaque élément estx : rest
(c'est-à-dire une liste qui ax
comme tête etrest
comme queue) pour chaque valeur différente dex
etrest
.Et bien sûr, comme Haskell est paresseux, la liste est progressivement générée selon les besoins, de sorte que vous pouvez évaluer partiellement des combinaisons exponentiellement grandes.
la source
Et voici grand-papa COBOL, la langue très décriée.
Supposons un tableau de 34 éléments de 8 octets chacun (sélection purement arbitraire.) L'idée est d'énumérer toutes les combinaisons possibles de 4 éléments et de les charger dans un tableau.
Nous utilisons 4 indices, un pour chaque position dans le groupe de 4
Le tableau est traité comme ceci:
Nous varions idx4 de 4 à la fin. Pour chaque idx4, nous obtenons une combinaison unique de groupes de quatre. Lorsque idx4 arrive à la fin du tableau, nous incrémentons idx3 de 1 et définissons idx4 sur idx3 + 1. Ensuite, nous exécutons à nouveau idx4 jusqu'à la fin. Nous procédons de cette manière, en augmentant idx3, idx2 et idx1 respectivement jusqu'à ce que la position de idx1 soit inférieure à 4 à partir de la fin du tableau. Cela termine l'algorithme.
Premières itérations:
Un exemple COBOL:
la source
Voici une implémentation élégante et générique dans Scala, comme décrit dans 99 Problèmes Scala .
la source
Si vous pouvez utiliser la syntaxe SQL - par exemple, si vous utilisez LINQ pour accéder aux champs d'une structure ou d'un tableau, ou accédez directement à une base de données qui a une table appelée "Alphabet" avec un seul champ de caractères "Letter", vous pouvez adapter ce qui suit code:
Cela renverra toutes les combinaisons de 3 lettres, quel que soit le nombre de lettres que vous avez dans le tableau "Alphabet" (cela peut être 3, 8, 10, 27, etc.).
Si ce que vous voulez, ce sont toutes les permutations, plutôt que les combinaisons (c'est-à-dire que vous voulez que "ACB" et "ABC" comptent comme différents, plutôt que d'apparaître une seule fois) supprimez simplement la dernière ligne (la ET) et c'est fait.
Post-édition: Après avoir relu la question, je me rends compte que ce qui est nécessaire est l' algorithme général , pas seulement spécifique pour le cas de la sélection de 3 éléments. La réponse d'Adam Hughes est la réponse complète, malheureusement je ne peux pas (encore) voter. Cette réponse est simple mais ne fonctionne que lorsque vous voulez exactement 3 éléments.
la source
Une autre version C # avec génération paresseuse des indices de combinaison. Cette version gère un seul tableau d'index pour définir un mappage entre la liste de toutes les valeurs et les valeurs de la combinaison actuelle, c'est-à-dire utilise constamment O (k) d' espace supplémentaire pendant toute la durée d'exécution. Le code génère des combinaisons individuelles, y compris la première, dans O (k) .
Code de test:
Production:
la source
c b a
ce qu'il ne contient pas.https://gist.github.com/3118596
Il existe une implémentation pour JavaScript. Il a des fonctions pour obtenir des k-combinaisons et toutes les combinaisons d'un tableau d'objets. Exemples:
la source
Voici une version évaluée paresseuse de cet algorithme codé en C #:
Et partie test:
J'espère que cela vous aidera!
la source
J'avais un algorithme de permutation que j'ai utilisé pour le projet euler, en python:
Si
vous devriez avoir toutes les combinaisons dont vous avez besoin sans répétition, en avez-vous besoin?
C'est un générateur, vous l'utilisez donc dans quelque chose comme ceci:
la source
la source
Version Clojure:
la source
Disons que votre tableau de lettres ressemble à ceci: "ABCDEFGH". Vous disposez de trois indices (i, j, k) indiquant quelles lettres vous allez utiliser pour le mot courant, vous commencez par:
D'abord, vous faites varier k, donc la prochaine étape ressemble à ceci:
Si vous avez atteint la fin, continuez et faites varier j puis k à nouveau.
Une fois que vous avez atteint G, vous commencez également à varier i.
Basé sur https://stackoverflow.com/a/127898/2628125 , mais plus abstrait, pour n'importe quelle taille de pointeurs.
la source
Tout est dit et fait ici vient le code O'caml pour cela. L'algorithme est évident d'après le code.
la source
Voici une méthode qui vous donne toutes les combinaisons de taille spécifiées à partir d'une chaîne de longueur aléatoire. Similaire à la solution de quinmars, mais fonctionne pour des entrées et k variés.
Le code peut être modifié pour envelopper, c'est-à-dire 'dab' de l'entrée 'abcd' wk = 3.
Sortie pour "abcde":
la source
code python court, donnant des positions d'index
la source
J'ai créé une solution dans SQL Server 2005 pour cela et je l'ai publiée sur mon site Web: http://www.jessemclain.com/downloads/code/sql/fn_GetMChooseNCombos.sql.htm
Voici un exemple pour montrer l'utilisation:
résultats:
la source
Voici ma proposition en C ++
J'ai essayé d'imposer aussi peu de restrictions que possible sur le type d'itérateur, de sorte que cette solution suppose simplement un itérateur de transfert, et il peut s'agir d'un const_iterator. Cela devrait fonctionner avec n'importe quel conteneur standard. Dans les cas où les arguments n'ont pas de sens, il lance std :: invalid_argumnent
la source
Voici un code que j'ai récemment écrit en Java, qui calcule et renvoie toute la combinaison des éléments "num" à partir des éléments "outOf".
la source
Une solution Javascript concise:
la source
Algorithme:
En C #:
Pourquoi ça marche?
Il existe une bijection entre les sous-ensembles d'un ensemble de n éléments et les séquences de n bits.
Cela signifie que nous pouvons déterminer le nombre de sous-ensembles en comptant les séquences.
Par exemple, les quatre éléments définis ci-dessous peuvent être représentés par {0,1} X {0, 1} X {0, 1} X {0, 1} (ou 2 ^ 4) séquences différentes.
Donc - tout ce que nous avons à faire est de compter de 1 à 2 ^ n pour trouver toutes les combinaisons. (Nous ignorons l'ensemble vide.) Ensuite, traduisez les chiffres en leur représentation binaire. Ensuite, remplacez les éléments de votre ensemble par des bits «on».
Si vous ne souhaitez que des résultats sur k éléments, imprimez uniquement lorsque k bits sont «activés».
(Si vous voulez tous les sous-ensembles au lieu des sous-ensembles de longueur k, supprimez la partie cnt / kElement.)
(Pour la preuve, voir le didacticiel gratuit MIT Mathematics for Computer Science, Lehman et al, section 11.2.2. Https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-042j-mathematics- for-computer-science-fall-2010 / lectures / )
la source
J'ai écrit une classe pour gérer les fonctions courantes pour travailler avec le coefficient binomial, qui est le type de problème auquel votre problème appartient. Il effectue les tâches suivantes:
Sort tous les K-index dans un format sympa pour tout N choisissez K dans un fichier. Les index K peuvent être remplacés par des chaînes ou des lettres plus descriptives. Cette méthode rend la résolution de ce type de problème assez triviale.
Convertit les K-index en l'index approprié d'une entrée dans la table des coefficients binomiaux triés. Cette technique est beaucoup plus rapide que les anciennes techniques publiées qui reposent sur l'itération. Il le fait en utilisant une propriété mathématique inhérente au Triangle de Pascal. Mon article en parle. Je crois que je suis le premier à découvrir et publier cette technique, mais je peux me tromper.
Convertit l'index d'une table de coefficients binomiaux triés en index K correspondants.
Utilise la méthode Mark Dominus pour calculer le coefficient binomial, qui est beaucoup moins susceptible de déborder et fonctionne avec de plus grands nombres.
La classe est écrite en .NET C # et fournit un moyen de gérer les objets liés au problème (le cas échéant) en utilisant une liste générique. Le constructeur de cette classe prend une valeur booléenne appelée InitTable qui, lorsqu'elle est vraie, créera une liste générique pour contenir les objets à gérer. Si cette valeur est fausse, elle ne créera pas la table. Il n'est pas nécessaire de créer le tableau pour exécuter les 4 méthodes ci-dessus. Des méthodes d'accesseur sont fournies pour accéder à la table.
Il existe une classe de test associée qui montre comment utiliser la classe et ses méthodes. Il a été largement testé avec 2 cas et il n'y a aucun bogue connu.
Pour en savoir plus sur cette classe et télécharger le code, voir Tablizing The Binomial Coeffieicent .
Il ne devrait pas être difficile de convertir cette classe en C ++.
la source