Trouver la n-ième permutation sans calculer les autres
Donné un tableau de N éléments représentant la permutation des atomes, est-il un algorithme comme ça:
function getNthPermutation( $atoms, $permutation_index, $size )
où $atoms
est le tableau des éléments, $permutation_index
est l'indice de la permutation et de la $size
est la taille de la permutation.
Par exemple:
$atoms = array( 'A', 'B', 'C' );
//getting third permutation of 2 elements
$perm = getNthPermutation( $atoms, 3, 2 );
echo implode( ', ', $perm )."\n";
Serait d'impression:
B, A
Sans calcul chaque permutation jusqu'à $permutation_index ?
J'ai entendu quelque chose à propos de factoradic permutations, mais à chaque application que j'ai trouvé donne comme résultat une permutation avec la même taille de V, qui n'est pas mon cas.
Grâce.
- qu'entendez-vous l'indice de la permutation?
- imaginez que vous imprimez chaque permutation de N éléments avec ses itération compteur (permutation de 0, la permutation de 1, de permutation 2, ... ) ... je veux de la n-ème de la permutation.
- mais qu'est ce qui détermine l'ordre de la permutation? je veux dire, permutation avec l'index 0 peut être l'une des formes
- je n'ai pas de soins sur le tri des permutations, tout fera l'affaire 🙂
- si vous n'avez pas de soins sur la commande, vous pouvez simplement choisir n'IMPORTE quelle permutation de taille $taille qui vous comme. vous souhaitez faire appel de cette fonction à plusieurs reprises, chaque fois avec un indice différent?
Vous devez vous connecter pour publier un commentaire.
Comme l'a déclaré RickyBobby, lorsque l'on considère le vocabulaire de l'ordre de permutations, vous devez utiliser la factorielle de décomposition à votre avantage.
À partir d'un point de vue pratique, c'est comment je le vois:
(n-1)!
,(n-2)!
, et ainsi de suite.i
-th quotient doit être un nombre entre0
etn-i-1
inclusive, oùi
va de0
àn-1
.Suivants du code C devrait vous donner une idée de comment cela fonctionne (
n
est le nombre d'entrées, eti
est l'indice de la permutation):Par exemple,
ithPermutation(10, 3628799)
imprime, comme prévu, la dernière permutation de dix éléments:Voici une solution qui vous permet de sélectionner la taille de la permutation. Par exemple, en plus d'être en mesure de générer toutes les permutations de 10 éléments, il peut générer des permutations de paires parmi 10 éléments. Aussi, il permute les listes d'objets arbitraires, et pas seulement les nombres entiers.
Exemple d'utilisation:
Comment ça fonctionne?
Il y a une idée très intéressante derrière elle. Prenons la liste
A, B, C, D
. Nous pouvons construire une permutation par les éléments de dessin de lui comme d'un jeu de cartes. D'abord, nous pouvons tirer de l'un des quatre éléments. Puis l'un des trois éléments restants, et ainsi de suite, jusqu'à ce que finalement nous n'avons plus rien.Ici est une séquence de choix. En commençant par le haut, nous passons à la troisième voie, la première, la seconde et la première. Et c'est notre permutation #13.
Penser à la façon, compte tenu de cette séquence de choix, vous devriez obtenir le nombre treize algorithmiquement. Faites l'inverse de l'algorithme, et c'est la façon dont vous pouvez reconstituer la séquence à partir d'un entier.
Nous allons essayer de trouver un schéma général pour l'emballage d'une séquence de choix dans un entier sans redondance, et le déballage de retour.
Un intéressant modèle est appelé nombre décimal du système. "27" peut être considéré comme le choix de chemin #2 sur 10, puis en choisissant le chemin n ° 7 sur 10.
Mais chaque chiffre ne peut encoder des choix à partir de 10 alternatives. D'autres systèmes qui ont un fixe radix, comme binaire et hexadécimal, aussi ne peut encoder des séquences de choix d'un nombre fixe de solutions de rechange. Nous voulons un système avec une variable radix, un peu comme les unités de temps, "14:05:29" 14 heures à partir de 24, 5 minutes à partir de 60, deuxième 29 à partir de la 60.
Que si nous prenons le générique de nombre en chaîne et chaîne-nombre de fonctions, et de les tromper en utilisant une combinaison de radixes? Au lieu de prendre une seule radix, comme parseInt('boeuf', 16) et (48879).toString(16), ils vont prendre un radix pour chaque chiffre.
Est-ce que même travail?
Et maintenant à l'envers:
C'est tellement beau. Maintenant, nous allons appliquer ce paramétrique système de nombre de le problème des permutations. Nous allons envisager de longueur 2 permutations de
A, B, C, D
. Quel est le nombre total d'entre eux? Voyons voir: tout d'abord, nous attirons l'un des 4 éléments, l'un des 3 autres, c'est4 * 3 = 12
manières de rédiger 2 articles. Ces 12 façons peuvent être emballés en nombres entiers [0..11]. Donc, imaginons que nous avons emballé déjà, et de tenter de le décompresser:Ces chiffres représentent des choix, pas d'index dans le tableau d'origine. [0, 0] ne veut pas dire prendre
A, A
, cela signifie la prise de l'élément de #0 à partir deA, B, C, D
(c'est Un), puis l'élément de #0 à partir du reste de la listeB, C, D
(c'est B). Et la permutation estA, B
.Un autre exemple: [3, 2] signifie la prise de l'élément n ° 3 de
A, B, C, D
(c'est D) et le point n ° 2 de la le reste de la listeA, B, C
(c'est C). Et la permutation estD, C
.Cette cartographie est appelé Lehmer code. Nous allons carte tous ces Lehmer codes de permutations:
C'est exactement ce dont nous avons besoin. Mais si vous regardez la
unpack
fonction, vous remarquerez qu'il produit des chiffres de droite à gauche (à l'inverse les actions depack
). Le choix de 3 sera décompressé avant le choix de 4. C'est malheureux, parce que nous voulons choisir une des 4 éléments avant de choisir à partir de 3. Sans être en mesure de le faire, nous devons calculer la Lehmer le premier code, l'accumuler dans un tableau temporaire, puis de l'appliquer sur le tableau d'éléments pour calculer l'effectif de permutation.Mais si nous ne nous soucions pas de l'ordre lexicographique, nous pouvons prétendre que nous voulons choisir à partir de 3 éléments avant de choisir à partir de 4. Ensuite, le choix de 4 sortira de
unpack
premier. En d'autres termes, nous allons utiliserunpack(n, [3, 4])
au lieu deunpack(n, [4, 3])
. Cette astuce permet de calculer le chiffre suivant du code de Lehmer et les appliquer immédiatement à la liste. Et c'est exactement commentnth_permutation()
œuvres.Une dernière chose que je veux mentionner, c'est que
unpack(i, [4, 3])
est étroitement liée à la factorielle du nombre de système. Regarder que le premier arbre de nouveau, si nous voulons que les permutations de taille 2 sans doublons, il nous suffit de passer chaque seconde permutation de l'index. Qui va nous donner 12 permutations de longueur 4, qui peut être coupé à la longueur 2.Il dépend de la façon dont vous "trier" votre permutations (ordre lexicographique par exemple).
Une façon de le faire est le factorielle du nombre de système, il vous donne une bijection entre [0 , n!] et toutes les permutations.
Alors pour tout nombre i dans [0,n!] vous pouvez calculer la i ' eme permutation sans calcul les autres.
Ce factorielle de l'écriture est basée sur le fait que n'importe quel nombre entre [ 0 et n!] peut être écrite comme :
(il est assez similaire à la base de la décomposition)
pour plus d'informations sur cette décomposition, ont un oeil à ce fil : https://math.stackexchange.com/questions/53262/factorial-decomposition-of-integers
espère que cela aide
Comme indiqué sur cette article de wikipedia cette approche est équivalent à calculer le lehmer code :
Donc le mieux que vous pouvez faire pour un ensemble de n élément est O(n ln(n)) avec une structure de données adaptée.
Voici un algorithme pour convertir entre des permutations et des rangs dans le temps linéaire. Toutefois, le classement qu'il utilise n'est pas lexicographique. C'est bizarre, mais cohérente. Je vais donner deux fonctions, l'une qui se convertit en un rang à une permutation, et celui qui fait l'inverse.
D'abord, à unrank (aller à partir du rang de permutation)
Prochain, à rang:
Le temps d'exécution de ces deux est O(n).
Il y a un beau, lisible papier expliquant pourquoi cela fonctionne: Classement & Unranking Permutations dans le Temps Linéaire, par Myrvold & Ruskey, Traitement de l'Information Lettres, Volume 79, Numéro 6, 30 septembre 2001, Pages 281-284.
http://webhome.cs.uvic.ca/~ruskey/Publications/RankPerm/MyrvoldRuskey.pdf
Ici est une courte et très rapide (linéaire en le nombre d'éléments) de la solution en python, travail de toute une liste d'éléments (les 13 premières lettres dans l'exemple ci-dessous) :
Exemples :
Note: je donne
letters[:]
(une copie deletters
) et pas de lettres parce que la fonction modifie les paramètreelems
(supprime l'élément choisi)Le code suivant calcule la kième permutation de n.
je.e n=3.
Les différentes permutations sont
123
132
213
231
312
321
Si k=5, retour 312.
En d'autres termes, il donne la kième vocabulaire de la permutation.
Il est calculable. C'est un code C# qui le fait pour vous.
Si vous stockez toutes les permutations dans la mémoire, par exemple dans un tableau, vous devriez être en mesure de ramener un à un, en O(1) fois.
Cela signifie que vous avez à stocker toutes les permutations, de sorte que si le calcul de toutes les permutations prend beaucoup de temps, ou de les stocker prend un trop grand espace, alors ce ne peut être une solution.
Ma suggestion serait d'essayer quand même, et de revenir si il est trop gros/lente, il n'y a aucun point de la recherche d'un "sage" solution si un naïf va faire le travail.