Trouver toutes les permutations possibles d'une chaîne donnée en python

89

J'ai une ficelle. Je souhaite générer toutes les permutations à partir de cette chaîne, en modifiant l'ordre des caractères. Par exemple, dites:

x='stack'

ce que je veux, c'est une liste comme celle-ci,

l=['stack','satck','sackt'.......]

Actuellement, je suis en train d'itérer sur la liste de cast de la chaîne, en sélectionnant 2 lettres au hasard et en les transposant pour former une nouvelle chaîne, et en l'ajoutant à la distribution de l. En fonction de la longueur de la chaîne, je calcule le nombre de permutations possibles et je continue les itérations jusqu'à ce que la taille définie atteigne la limite. Il doit y avoir une meilleure façon de faire cela.

Nihar Sarangi
la source

Réponses:

143

Le module itertools a une méthode utile appelée permutations (). La documentation dit:

itertools.permutations (itérable [, r])

Renvoie des permutations successives de longueur r des éléments de l'itérable.

Si r n'est pas spécifié ou est None, alors r prend par défaut la longueur de l'itérable et toutes les permutations de pleine longueur possibles sont générées.

Les permutations sont émises dans l'ordre de tri lexicographique. Ainsi, si l'itérable d'entrée est trié, les tuples de permutation seront produits dans l'ordre trié.

Vous devrez cependant joindre vos lettres permutées sous forme de chaînes.

>>> from itertools import permutations
>>> perms = [''.join(p) for p in permutations('stack')]
>>> perms

['stack', 'stakc', 'stcak', 'stcka', 'stkac', 'stkca', 'satck', 'satkc', 'sactk', 'sackt', 'saktc', 'sakct', ' sctak ',' sctka ',' scatk ',' scakt ',' sckta ',' sckat ',' sktac ',' sktca ',' skatc ',' skact ',' skcta ',' skcat ',' tsack ' , 'tsakc', 'tscak', 'tscka', 'tskac', 'tskca', 'tasck', 'taskc', 'tacsk', 'tacks', 'taksc', 'takcs', 'tcsak', ' tcska ',' tcask ',' tcaks ',' tcksa ',' tckas ',' tksac ',' tksca ',' tkasc ',' tkacs ',' tkcsa ',' tkcas ',' astck ','astkc ',' asctk ',' asckt ',' asktc ',' askct ',' atsck ',' atskc ',' atcsk ',' atcks ',' atksc ',' atkcs ',' acstk ',' acskt ' , 'actesk', 'actks', 'ackst', 'ackts', 'akstc', 'aksct', 'aktsc', 'aktcs', 'akcst', 'akcts', 'cstak', 'cstka', ' csatk ',' csakt ',' cskta ',' cskat ',' ctsak ',' ctska ',' ctask ',' ctaks ',' ctksa ',' ctkas ',' castk ',' caskt ',' catsk ' , 'catks', 'cakst', 'cakts', 'cksta', 'cksat', 'cktsa', 'cktas', 'ckast', 'ckats', 'kstac', 'kstca', 'ksatc','ksact', 'kscta', 'kscat', 'ktsac', 'ktsca', 'ktasc', 'ktacs', 'ktcsa', 'ktcas', 'kastc', 'kasct', 'katsc', 'katcs ',' kacst ',' kacts ',' kcsta ',' kcsat ',' kctsa ',' kctas ',' kcast ',' kcats ']

Si vous vous trouvez troublé par des doublons, essayez d'ajuster vos données dans une structure sans doublons comme set:

>>> perms = [''.join(p) for p in permutations('stacks')]
>>> len(perms)
720
>>> len(set(perms))
360

Merci à @pst d'avoir souligné que ce n'est pas ce que nous considérons traditionnellement comme un cast de type, mais plutôt un appel au set()constructeur.

désir de machine
la source
3
Nit: set(...)ne «lance» pas. Au contraire, il génère (et produit) l'ensemble représentant la collection d'entrée: une fois généré, il n'a aucune association avec la collection d'entrée (et est un objet différent, pas seulement une vue différente).
@pst: Hmm, j'ai tendance à être en désaccord. Je sais dans Ada ou Pascal qu'un casting est juste une nouvelle vue de type sur les mêmes bits. Cependant, au moins du point de vue C, la diffusion est un terme approprié, que vous changiez ou non la structure sous-jacente des données. Il fait simplement référence à la conversion de type explicite. Veuillez expliquer mon malentendu si vous le pouvez.
machine désirant
1
Typographie . Bien que, comme vous le faites remarquer, cela puisse être différent d'une simple vue, j'aime essayer de garder les concepts séparés pour éviter toute confusion. J'aurais dû mentionner explicitement "coercition" dans mon premier commentaire, même si je considérerais simplement set a function: list -> set.
1
Je le visualise bool, est une fonction qui évalue un booléen (Vrai / Faux) en fonction de l'entrée. Je trouve que l'utilisation de "cast" ici est fausse et trompeuse ...
1
En tant que mise à jour intéressante, la documentation a depuis été modifiée pour indiquer que la fonction intégrée bool () peut être utilisée pour convertir n'importe quelle valeur en booléen , en particulier convertir plutôt que cast. Cela s'est produit dans la version ultérieure de cette discussion, ce qui m'a amené à croire que cette discussion a conduit à un changement dans la documentation!
machine désirant
45

Vous pouvez obtenir tous les N! permutations sans trop de code

def permutations(string, step = 0):

    # if we've gotten to the end, print the permutation
    if step == len(string):
        print "".join(string)

    # everything to the right of step has not been swapped yet
    for i in range(step, len(string)):

        # copy the string (store as array)
        string_copy = [character for character in string]

        # swap the current index with the step
        string_copy[step], string_copy[i] = string_copy[i], string_copy[step]

        # recurse on the portion of the string that has not been swapped yet (now it's index will begin with step + 1)
        permutations(string_copy, step + 1)
illerucis
la source
joli. Fonctionne parfaitement
kishorer747
1
Je l'ai juste légèrement modifié, nous n'avons pas besoin d'échanger les variables si i == step
siraj
4
Le runtime est O (n!) Car il y en a n! permutations.
Aspen
Pourquoi utilisez-vous step == len(string)au lieu de step == len(string) - 1?
tulians
Parce qu'alors les 2 derniers éléments ne seraient jamais échangés. Essayez 'abc' jusqu'à ce que b et c soient échangés.
Roman Riesen
14

Voici une autre façon de faire la permutation de chaîne avec un code minimal. Nous créons essentiellement une boucle, puis nous continuons à échanger deux caractères à la fois, à l'intérieur de la boucle, nous aurons la récursivité. Remarquez, nous n'imprimons que lorsque les indexeurs atteignent la longueur de notre chaîne. Exemple: ABC i pour notre point de départ et notre paramètre de récursivité j pour notre boucle

voici une aide visuelle comment ça marche de gauche à droite de haut en bas (c'est l'ordre de permutation)

entrez la description de l'image ici

le code :

def permute(data, i, length): 
    if i==length: 
        print(''.join(data) )
    else: 
        for j in range(i,length): 
            #swap
            data[i], data[j] = data[j], data[i] 
            permute(data, i+1, length) 
            data[i], data[j] = data[j], data[i]  


string = "ABC"
n = len(string) 
data = list(string) 
permute(data, 0, n)
grepit
la source
5
Il pourrait être utile de mentionner que c'est la base du paradigme du bactracking .
AruniRC
Plus d'infos, codes identiques / similaires: geeksforgeeks.org / ... J'aime mieux votre exemple avec l'exemple graphique;)
CTS_AE
8

Les utilisateurs de Stack Overflow ont déjà publié des solutions solides, mais je voulais montrer encore une autre solution. Celui-ci je trouve plus intuitif

L'idée est que pour une chaîne donnée: on peut récurer par l'algorithme (pseudo-code):

permutations = char + permutations (string - char) for char in string

J'espère que cela aide quelqu'un!

def permutations(string):
    """
    Create all permutations of a string with non-repeating characters
    """
    permutation_list = []
    if len(string) == 1:
        return [string]
    else:
        for char in string:
            [permutation_list.append(char + a) for a in permutations(string.replace(char, "", 1))]
    return permutation_list
BushMinusZero
la source
4
Cela ne fonctionnera pas dans les cas où il y a des caractères répétitifs (str.replace). Par exemple: rqqx
sanjay
Utilisez: [permutation_list.append (char + a) for a in permutations (string.replace (char, "", 1))]
user3761855
7

Voici une fonction simple pour renvoyer des permutations uniques:

def permutations(string):
    if len(string) == 1:
        return string

    recursive_perms = []
    for c in string:
        for perm in permutations(string.replace(c,'',1)):
            revursive_perms.append(c+perm)

    return set(revursive_perms)
ArashkG
la source
6
1. Vous avez une faute de frappe: revursive_perms-> recursive_perms. 2. Cela permettrait d'économiser de la RAM et du temps s'il recursive_permss'agissait d'un ensemble plutôt qu'une liste que vous convertissez en un ensemble dans l'instruction return. 3. Il serait plus efficace d'utiliser le découpage de chaînes au lieu de .replaceconstruire l'argument selon l'appel récursif de permutations. 4. Ce n'est pas une bonne idée de l'utiliser stringcomme nom de variable car cela occulte le nom du stringmodule standard .
PM 2 Ring
5

Voici une autre approche différente de ce que @Adriano et @illerucis ont publié. Cela a un meilleur temps d'exécution, vous pouvez le vérifier vous-même en mesurant le temps:

def removeCharFromStr(str, index):
    endIndex = index if index == len(str) else index + 1
    return str[:index] + str[endIndex:]

# 'ab' -> a + 'b', b + 'a'
# 'abc' ->  a + bc, b + ac, c + ab
#           a + cb, b + ca, c + ba
def perm(str):
    if len(str) <= 1:
        return {str}
    permSet = set()
    for i, c in enumerate(str):
        newStr = removeCharFromStr(str, i)
        retSet = perm(newStr)
        for elem in retSet:
            permSet.add(c + elem)
    return permSet

Pour une chaîne arbitraire "dadffddxcf", il a fallu 1,1336 sec pour la bibliothèque de permutation, 9,125 sec pour cette implémentation et 16,357 sec pour la version de @ Adriano et @illerucis. Bien sûr, vous pouvez toujours l'optimiser.

Rooky
la source
4

itertools.permutationsc'est bien, mais cela ne gère pas bien les séquences qui contiennent des éléments répétés. En effet, en interne, il permute les indices de séquence et ignore les valeurs des éléments de séquence.

Bien sûr, il est possible de filtrer la sortie de itertools.permutationsvia un ensemble pour éliminer les doublons, mais cela perd encore du temps à générer ces doublons, et s'il y a plusieurs éléments répétés dans la séquence de base, il y en aura beaucoup de doublons. En outre, l'utilisation d'une collection pour contenir les résultats gaspille de la RAM, annulant l'avantage d'utiliser un itérateur en premier lieu.

Heureusement, il existe des approches plus efficaces. Le code ci-dessous utilise l'algorithme du mathématicien indien du 14ème siècle Narayana Pandita, que l'on peut trouver dans l'article de Wikipédia sur la permutation . Cet algorithme ancien est toujours l'un des moyens connus les plus rapides pour générer des permutations dans l'ordre, et il est assez robuste, en ce sens qu'il gère correctement les permutations qui contiennent des éléments répétés.

def lexico_permute_string(s):
    ''' Generate all permutations in lexicographic order of string `s`

        This algorithm, due to Narayana Pandita, is from
        https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order

        To produce the next permutation in lexicographic order of sequence `a`

        1. Find the largest index j such that a[j] < a[j + 1]. If no such index exists, 
        the permutation is the last permutation.
        2. Find the largest index k greater than j such that a[j] < a[k].
        3. Swap the value of a[j] with that of a[k].
        4. Reverse the sequence from a[j + 1] up to and including the final element a[n].
    '''

    a = sorted(s)
    n = len(a) - 1
    while True:
        yield ''.join(a)

        #1. Find the largest index j such that a[j] < a[j + 1]
        for j in range(n-1, -1, -1):
            if a[j] < a[j + 1]:
                break
        else:
            return

        #2. Find the largest index k greater than j such that a[j] < a[k]
        v = a[j]
        for k in range(n, j, -1):
            if v < a[k]:
                break

        #3. Swap the value of a[j] with that of a[k].
        a[j], a[k] = a[k], a[j]

        #4. Reverse the tail of the sequence
        a[j+1:] = a[j+1:][::-1]

for s in lexico_permute_string('data'):
    print(s)

production

aadt
aatd
adat
adta
atad
atda
daat
data
dtaa
taad
tada
tdaa

Bien sûr, si vous souhaitez rassembler les chaînes générées dans une liste, vous pouvez faire

list(lexico_permute_string('data'))

ou dans les versions récentes de Python:

[*lexico_permute_string('data')]
PM 2Bague
la source
Magnifiquement expliqué.
lmao
2

pourquoi ne faites-vous pas simplement:

from itertools import permutations
perms = [''.join(p) for p in permutations(['s','t','a','c','k'])]
print perms
print len(perms)
print len(set(perms))

vous n'obtenez aucun duplicata comme vous pouvez le voir:

 ['stack', 'stakc', 'stcak', 'stcka', 'stkac', 'stkca', 'satck', 'satkc', 
'sactk', 'sackt', 'saktc', 'sakct', 'sctak', 'sctka', 'scatk', 'scakt', 'sckta',
 'sckat', 'sktac', 'sktca', 'skatc', 'skact', 'skcta', 'skcat', 'tsack', 
'tsakc', 'tscak', 'tscka', 'tskac', 'tskca', 'tasck', 'taskc', 'tacsk', 'tacks', 
'taksc', 'takcs', 'tcsak', 'tcska', 'tcask', 'tcaks', 'tcksa', 'tckas', 'tksac', 
'tksca', 'tkasc', 'tkacs', 'tkcsa', 'tkcas', 'astck', 'astkc', 'asctk', 'asckt', 
'asktc', 'askct', 'atsck', 'atskc', 'atcsk', 'atcks', 'atksc', 'atkcs', 'acstk', 
'acskt', 'actsk', 'actks', 'ackst', 'ackts', 'akstc', 'aksct', 'aktsc', 'aktcs', 
'akcst', 'akcts', 'cstak', 'cstka', 'csatk', 'csakt', 'cskta', 'cskat', 'ctsak', 
'ctska', 'ctask', 'ctaks', 'ctksa', 'ctkas', 'castk', 'caskt', 'catsk', 'catks', 
'cakst', 'cakts', 'cksta', 'cksat', 'cktsa', 'cktas', 'ckast', 'ckats', 'kstac', 
'kstca', 'ksatc', 'ksact', 'kscta', 'kscat', 'ktsac', 'ktsca', 'ktasc', 'ktacs', 
'ktcsa', 'ktcas', 'kastc', 'kasct', 'katsc', 'katcs', 'kacst', 'kacts', 'kcsta', 
'kcsat', 'kctsa', 'kctas', 'kcast', 'kcats']
    120
    120
    [Finished in 0.3s]
Vincenzo
la source
4
Non, vous obtenez toujours des doublons (ou pire) si vous avez deux ou plusieurs lettres identiques. C'était le cas dans l'exemple de @ machineyearning, car il utilisait le mot stack au lieu de stack . Cela signifie que votre solution ne fonctionne que pour les mots contenant des caractères uniques.
erik le
2
def permute(seq):
    if not seq:
        yield seq
    else:
        for i in range(len(seq)):
            rest = seq[:i]+seq[i+1:]
            for x in permute(rest):
                yield seq[i:i+1]+x

print(list(permute('stack')))
Srivastava
la source
2
Pouvez-vous expliquer pourquoi votre solution est meilleure que celles déjà fournies?
Noel Widmer
Je n'ai pas dit que ma solution était meilleure que les autres. Je viens de fournir ma solution pour faire cela.
Srivastava
1

Voir itertools.combinationsou itertools.permutations.

Brian Cain
la source
4
les combinaisons ne sont pas pertinentes pour son problème. il transpose des lettres, ce qui signifie que l'ordre est pertinent, ce qui ne signifie que des permutations
machine aspirant
1

Voici une version légèrement améliorée du code d' illerucis pour renvoyer une liste de toutes les permutations d'une chaîne savec des caractères distincts (pas nécessairement dans l'ordre de tri lexicographique), sans utiliser itertools:

def get_perms(s, i=0):
    """
    Returns a list of all (len(s) - i)! permutations t of s where t[:i] = s[:i].
    """
    # To avoid memory allocations for intermediate strings, use a list of chars.
    if isinstance(s, str):
        s = list(s)

    # Base Case: 0! = 1! = 1.
    # Store the only permutation as an immutable string, not a mutable list.
    if i >= len(s) - 1:
        return ["".join(s)]

    # Inductive Step: (len(s) - i)! = (len(s) - i) * (len(s) - i - 1)!
    # Swap in each suffix character to be at the beginning of the suffix.
    perms = get_perms(s, i + 1)
    for j in range(i + 1, len(s)):
        s[i], s[j] = s[j], s[i]
        perms.extend(get_perms(s, i + 1))
        s[i], s[j] = s[j], s[i]
    return perms
Adriano
la source
1

Encore une initiative et une solution récursive. L'idée est de sélectionner une lettre comme pivot puis de créer un mot.

# for a string with length n, there is a factorial n! permutations
alphabet = 'abc'
starting_perm = ''
# with recursion
def premuate(perm, alphabet):
    if not alphabet: # we created one word by using all letters in the alphabet
        print(perm + alphabet)
    else:
        for i in range(len(alphabet)): # iterate over all letters in the alphabet
            premuate(perm + alphabet[i], alphabet[0:i] + alphabet[i+1:]) # chose one letter from the alphabet

# call it            
premuate(starting_perm, alphabet)

Production:

abc
acb
bac
bca
cab
cba
Faroq AL-Tam
la source
0

Voici une version de générateur vraiment simple:

def find_all_permutations(s, curr=[]):
    if len(s) == 0:
        yield curr
    else:
        for i, c in enumerate(s):
            for combo in find_all_permutations(s[:i]+s[i+1:], curr + [c]):
                yield "".join(combo)

Je pense que ce n'est pas si mal!

Gritty Kitty
la source
0
def f(s):
  if len(s) == 2:
    X = [s, (s[1] + s[0])]
      return X
else:
    list1 = []
    for i in range(0, len(s)):
        Y = f(s[0:i] + s[i+1: len(s)])
        for j in Y:
            list1.append(s[i] + j)
    return list1
s = raw_input()
z = f(s)
print z
Ritabrata Sanyal
la source
veuillez essayer d'ajouter une description.
Arun Vinoth
0
from itertools import permutations
perms = [''.join(p) for p in permutations('ABC')]

perms = [''.join(p) for p in permutations('stack')]
Satish Kumar
la source
5
veuillez essayer d'ajouter une description.
Arun Vinoth
0
def perm(string):
   res=[]
   for j in range(0,len(string)):
       if(len(string)>1):
           for i in perm(string[1:]):
               res.append(string[0]+i)
       else:
           return [string];
       string=string[1:]+string[0];
   return res;
l=set(perm("abcde"))

C'est une façon de générer des permutations avec récursivité, vous pouvez facilement comprendre le code en prenant les chaînes 'a', 'ab' et 'abc' comme entrée.

Vous obtenez tous les N! permutations avec cela, sans doublons.

Jasser
la source
0

Tout le monde aime l'odeur de son propre code. Je partage simplement celui que je trouve le plus simple:

def get_permutations(word):
    if len(word) == 1:
        yield word

    for i, letter in enumerate(word):
        for perm in get_permutations(word[:i] + word[i+1:]):
            yield letter + perm
r_2
la source
0

Ce programme n'élimine pas les doublons, mais je pense que c'est l'une des approches les plus efficaces:

s=raw_input("Enter a string: ")
print "Permutations :\n",s
size=len(s)
lis=list(range(0,size))
while(True):
    k=-1
    while(k>-size and lis[k-1]>lis[k]):
        k-=1
    if k>-size:
        p=sorted(lis[k-1:])
        e=p[p.index(lis[k-1])+1]
        lis.insert(k-1,'A')
        lis.remove(e)
        lis[lis.index('A')]=e
        lis[k:]=sorted(lis[k:])
        list2=[]
        for k in lis:
                list2.append(s[k])
        print "".join(list2)
    else:
                break
Nagaraju Chukkala
la source
0
def permute_all_chars(list, begin, end):

    if (begin == end):
        print(list)
        return

    for current_position in range(begin, end + 1):
        list[begin], list[current_position] = list[current_position], list[begin]
        permute_all_chars(list, begin + 1, end)
        list[begin], list[current_position] = list[current_position], list[begin]


given_str = 'ABC'
list = []
for char in given_str:
    list.append(char)
permute_all_chars(list, 0, len(list) -1)
Chandra Sekhar Battini
la source
veuillez essayer d'ajouter une description.
Arun Vinoth
0

Solution plus simple utilisant des permutations.

from itertools import permutations

def stringPermutate(s1):
    length=len(s1)
    if length < 2:
        return s1

    perm = [''.join(p) for p in permutations(s1)]

    return set(perm)
Nelson Katale
la source
0

Tous les mots possibles avec pile

from itertools import permutations
for i in permutations('stack'):
    print(''.join(i))
permutations(iterable, r=None)

Renvoie des permutations successives de longueur r des éléments de l'itérable.

Si r n'est pas spécifié ou est None, alors r prend par défaut la longueur de l'itérable et toutes les permutations de pleine longueur possibles sont générées.

Les permutations sont émises dans l'ordre de tri lexicographique. Ainsi, si l'itérable d'entrée est trié, les tuples de permutation seront produits dans l'ordre trié.

Les éléments sont traités comme uniques en fonction de leur position et non de leur valeur. Donc, si les éléments d'entrée sont uniques, il n'y aura pas de valeurs de répétition dans chaque permutation.

CodePerfectPlus
la source
0

Il s'agit d'une solution récursive avec n!laquelle accepte les éléments en double dans la chaîne

import math

def getFactors(root,num):
    sol = []
    # return condition
    if len(num) == 1:
            return [root+num]
    # looping in next iteration
    for i in range(len(num)):  
        # Creating a substring with all remaining char but the taken in this iteration
        if i > 0:
            rem = num[:i]+num[i+1:]
        else:
            rem = num[i+1:]
        # Concatenating existing solutions with the solution of this iteration
        sol = sol + getFactors(root + num[i], rem)
    return sol

J'ai validé la solution en tenant compte de deux éléments, le nombre de combinaisons est n!et le résultat ne peut pas contenir de doublons. Donc:

inpt = "1234"
results = getFactors("",inpt)

if len(results) == math.factorial(len(inpt)) | len(results) != len(set(results)):
    print("Wrong approach")
else:
    print("Correct Approach")
Ignacio Alorre
la source
-1

Voici une implémentation récursive simple et directe;

def stringPermutations(s):
    if len(s) < 2:
        yield s
        return
    for pos in range(0, len(s)):
        char = s[pos]
        permForRemaining = list(stringPermutations(s[0:pos] + s[pos+1:]))
        for perm in permForRemaining:
            yield char + perm
iBe
la source
1
Vous devez corriger l'indentation. Il n'est pas nécessaire d'enregistrer les résultats de l'appel récursif stringPermutationsdans une liste - vous pouvez effectuer une itération directement dessus, par exemple for perm in stringPermutations(s[:pos] + s[pos+1:]):. En outre, vous pouvez simplifier la forboucle en utilisant au enumeratelieu de rangeet éliminer la char = s[pos]cession: for pos, char in enumerate(s):.
PM 2 Ring
-1

Avec récursivité

# swap ith and jth character of string
def swap(s, i, j):
    q = list(s)
    q[i], q[j] = q[j], q[i]
    return ''.join(q)


# recursive function 
def _permute(p, s, permutes):
    if p >= len(s) - 1:
        permutes.append(s)
        return

    for i in range(p, len(s)):
        _permute(p + 1, swap(s, p, i), permutes)


# helper function
def permute(s):
    permutes = []
    _permute(0, s, permutes)
    return permutes


# TEST IT
s = "1234"
all_permute = permute(s)
print(all_permute)

Avec une approche itérative (en utilisant Stack)

# swap ith and jth character of string
def swap(s, i, j):
    q = list(s)
    q[i], q[j] = q[j], q[i]
    return ''.join(q)


# iterative function
def permute_using_stack(s):
    stk = [(0, s)]

    permutes = []

    while len(stk) > 0:
        p, s = stk.pop(0)

        if p >= len(s) - 1:
            permutes.append(s)
            continue

        for i in range(p, len(s)):
            stk.append((p + 1, swap(s, p, i)))

    return permutes


# TEST IT
s = "1234"
all_permute = permute_using_stack(s)
print(all_permute)

Avec tri lexicographique

# swap ith and jth character of string
def swap(s, i, j):
    q = list(s)
    q[i], q[j] = q[j], q[i]
    return ''.join(q)


# finds next lexicographic string if exist otherwise returns -1
def next_lexicographical(s):
    for i in range(len(s) - 2, -1, -1):
        if s[i] < s[i + 1]:
            m = s[i + 1]
            swap_pos = i + 1

            for j in range(i + 1, len(s)):
                if m > s[j] > s[i]:
                    m = s[j]
                    swap_pos = j

            if swap_pos != -1:
                s = swap(s, i, swap_pos)
                s = s[:i + 1] + ''.join(sorted(s[i + 1:]))
                return s

    return -1


# helper function
def permute_lexicographically(s):
    s = ''.join(sorted(s))
    permutes = []
    while True:
        permutes.append(s)
        s = next_lexicographical(s)
        if s == -1:
            break
    return permutes


# TEST IT
s = "1234"
all_permute = permute_lexicographically(s)
print(all_permute)
bikram
la source