Voici un algorithme rapide qui produit une chaîne courte contenant toutes les permutations. Je suis sûr qu'il donne la réponse la plus courte possible, mais je n'ai pas une preuve complète en main.
Explication. Ci-dessous un arbre de toutes les permutations. L'image est incomplète. Imaginez que l'arbre continue pour toujours vers la droite.
1 --+-- 12 --+-- 123 ...
| |
| +-- 231 ...
| |
| +-- 312 ...
|
+-- 21 --+-- 213 ...
|
+-- 132 ...
|
+-- 321 ...
Les nœuds au niveau k de cet arbre sont toutes les permutations de longueur k. En outre, les permutations sont dans un ordre particulier avec un lot de chevauchement entre chaque permutation et ses voisins au-dessus et au-dessous de .
Pour être précis, le premier enfant de chaque nœud est trouvé en ajoutant simplement le symbole suivant à la fin. Par exemple, le premier enfant de 213 serait 2134. Le reste des enfants sont trouvés en tournant au premier enfant à gauche un symbole à une fois. La rotation 2134 produirait 1342, 3421, 4213.
Compte tenu de tous les noeuds à un niveau donné et les enchaînant, qui se chevauchent autant que possible, produit les chaînes 1, 121, 123121321, etc.
Le longueur de la n cette chaîne est the sum for x=1 to n of x!. (Vous pouvez le prouver en observant à quel point non-chevauchement qui existe entre les permutations voisines frères et soeurs se chevauchent dans tout sauf 1 symbole;. Cousins germains se chevauchent dans tout sauf 2 symboles,. Etc.)
Esquisse de la preuve. Je n'ai pas complètement prouvé que c'est la meilleure solution, mais voici un croquis de la façon dont la preuve procéderait. Tout d'abord montrer que toute chaîne contenant n permutations distinctes a une longueur n - 1. Ensuite, montrer que l'ajout d'une chaîne contenant n +1 permutations distinctes a une longueur de 2 n + 1. C'est, l'ajout d'un plus la permutation vous coûtera deux chiffres. Procéder en calculant la longueur minimale de chaînes contenant n P r et n P r + 1 permutations distinctes, jusqu'à n!. En bref, cette séquence est optimale parce que vous ne pouvez pas l'aggraver quelque part dans l'espoir de l'améliorer ailleurs. C'est déjà localement optimal partout. Tous les mouvements sont forcés.
Algorithme. Compte tenu de tout ce contexte, l'algorithme est très simple. Marcher cet arbre à la profondeur désirée et enchaîner tous les nœuds à cette profondeur.
Heureusement, nous n'avons pas besoin de construire l'arbre en mémoire.
def build(node, s):
"""String together all descendants of the given node at the target depth."""
d = len(node) # depth of this node. depth of "213" is 3.
n = len(s) # target depth
if d == n - 1:
return node + s[n - 1] + node # children of 213 join to make "2134213"
else:
c0 = node + s[d] # first child node
children = [c0[i:] + c0[:i] for i in range(d + 1)] # all child nodes
strings = [build(c, s) for c in children] # recurse to the desired depth
for j in range(1, d + 1):
strings[j] = strings[j][d:] # cut off overlap with previous sibling
return ''.join(strings) # join what's left
def stringContainingAllPermutationsOf(s):
return build(s[:1], s)
Performances. Le code ci-dessus est déjà beaucoup plus rapide que mon autre solution, et il fait beaucoup de couper et coller de grandes chaînes que vous pouvez optimiser. L'algorithme peut être fait pour fonctionner dans le temps et la mémoire proportionnelle à la taille de la sortie.
Problème intéressant. Je ne connais même pas la longueur de la séquence la plus courte. Une limite inférieure est n! + n - 1, puisqu'il y a n! permutations distinctes et chacune doit avoir un point de départ distinct dans la séquence. Une borne supérieure est (n-1)! (2n-1), que vous pouvez réaliser en choisissant arbitrairement un élément, puis en enchaînant un "cycle complet" de chaque permutation se terminant avec cet élément, soit presque deux copies de la permutation, comme dans 234512345. Il y a (n-1)! de telles permutations, et chaque cycle est de longueur (2n-1). –
Est-ce que la réponse que vous avez choisie est la bonne (et la meilleure) réponse – Xolve