在python中查找给定字符串的所有可能排列

时间:2011-11-29 06:12:34

标签: python string permutation

我有一个字符串。我想通过改变字符串中的字符顺序从该字符串生成所有排列。例如,说:

x='stack'

我想要的是这样的列表,

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

目前我正在迭代字符串的列表转换,随机挑选2个字母并转置它们以形成新字符串,并将其添加到l的设置转换中。根据字符串的长度,我计算可能的排列数,并继续迭代,直到设置大小达到限制。 必须有更好的方法来做到这一点。

25 个答案:

答案 0 :(得分:112)

itertools模块有一个名为permutations()的有用方法。 The documentation说:

  

itertools.permutations(iterable [,r])

     

返回迭代中元素的连续r长度排列。

     

如果未指定r或为None,则r默认为长度   可迭代且生成所有可能的全长排列。

     

排列以字典排序顺序发出。所以,如果输入   对iterable进行排序,排序元组将按排序生成   顺序。

你必须将你的置换字母作为字符串加入。

>>> 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','actk',   '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']

如果您发现自己受到重复项的困扰,请尝试将数据拟合到一个没有重复项的结构中,例如set

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

感谢@pst指出这不是我们传统上认为的类型转换,而是更多地调用set()构造函数。

答案 1 :(得分:32)

你可以获得所有N!没有太多代码的排列

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)

答案 2 :(得分:6)

堆栈溢出用户已经发布了一些强大的解决方案,但我想展示另一种解决方案。这个我觉得更直观

这个想法是对于给定的字符串:我们可以通过算法递归(伪代码):

  

permutations =字符串

中char的char + permutations(string - char)

希望它有所帮助!

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, ""))]
    return permutation_list

答案 3 :(得分:5)

这是一个返回唯一排列的简单函数:

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)

答案 4 :(得分:5)

这是另一种不同于@Adriano和@illerucis发布的方法。这有一个更好的运行时间,您可以通过测量时间来检查自己:

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

对于任意字符串&#34; dadffddxcf&#34;排列库需要1.1336秒,这个实现需要9.125秒,@ Adriano和@ illerucis&#39;需要16.357秒。版。当然你仍然可以优化它。

答案 5 :(得分:4)

这是用最少的代码完成字符串置换的另一种方法。 我们基本上是创建一个循环,然后一次交换两个字符, 在循环内部,我们将进行递归。注意,我们仅在索引器达到字符串长度时才打印。 例: 美国广播公司 我是我们的出发点和递归参数 j为我们的循环

这是从左到右,从上到下(排列顺序)的视觉帮助

enter image description here

代码:

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)

答案 6 :(得分:3)

itertools.permutations很好,但它不能很好地处理包含重复元素的序列。那是因为在内部它会置换序列索引并且不知道序列项值。

当然,可以通过一个集合来过滤itertools.permutations的输出以消除重复项,但它仍然会浪费时间来生成这些重复项,如果基本序列中有多个重复元素,则会有批次重复。此外,使用集合来保存结果会浪费RAM,从而否定了首先使用迭代器的好处。

幸运的是,有更有效的方法。下面的代码使用了14世纪印度数学家Narayana Pandita的算法,该算法可以在Wikipedia article on Permutation中找到。这种古老的算法仍然是按顺序生成排列的最快的已知方法之一,它非常健壮,因为它可以正确处理包含重复元素的排列。

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)

<强>输出

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

当然,如果您想将所产生的字符串收集到列表中,您可以

list(lexico_permute_string('data'))

或最近的Python版本:

[*lexico_permute_string('data')]

答案 7 :(得分:2)

为什么你不简单呢:

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))

你没有重复,你可以看到:

 ['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]

答案 8 :(得分:1)

采用递归方法。

def permute(word):
    if len(word) == 1:
        return [word]
    permutations = permute(word[1:])
    character = word[0]
    result = []
    for p in permutations:
        for i in range(len(p)+1):
            result.append(p[:i] + character + p[i:])
    return result




running code.

>>> permute('abc')
['abc', 'bac', 'bca', 'acb', 'cab', 'cba']

答案 9 :(得分:1)

<name> has been eliminated.
<name> has won.
Players left are <name list>.

答案 10 :(得分:1)

答案 11 :(得分:0)

这是一个n!的递归解决方案,它可以接受字符串中重复的元素

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

我通过考虑两个元素验证了该解决方案,组合的数量为n!,结果中不能包含重复项。所以:

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

if len(results) == math.factorial(len(inpt)) | len(results) != len(set(results)):
    print("Wrong approach")
else:
    print("Correct Approach")

答案 12 :(得分:0)

所有可能的单词都带有堆栈

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

返回可迭代元素的连续r长度排列。

如果未指定r或为None,则r默认为可迭代的长度,并生成所有可能的全长排列。

排列以字典顺序排序。因此,如果对输入的iterable进行排序,则将按排序顺序生成排列元组。

根据元素的位置而不是它们的值将它们视为唯一。因此,如果输入元素是唯一的,则每个排列中都不会有重复值。

答案 13 :(得分:0)

还有另一个主动和递归的解决方案。这个想法是选择一个字母作为枢轴,然后创建一个单词。

# 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)

输出:

abc
acb
bac
bca
cab
cba

答案 14 :(得分:0)

使用排列的简单解决方案。

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)

答案 15 :(得分: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)

答案 16 :(得分: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"))

这是通过递归生成排列的一种方法,您可以通过使用字符串来轻松理解代码。&#39; a&#39; ab&#39; &安培; &#39; ABC&#39;作为输入。

你得到全部N!这种排列,没有重复。

答案 17 :(得分:0)

这个程序并没有消除重复,但我认为这是最有效的方法之一:

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

答案 18 :(得分:0)

每个人都喜欢自己的代码气味。只是分享一个我觉得最简单的那个:

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

答案 19 :(得分:0)

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

perms = [''.join(p) for p in permutations('stack')]

答案 20 :(得分: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

答案 21 :(得分:0)

这是一个非常简单的生成器版本:

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)

我觉得它不是那么糟糕!

答案 22 :(得分:-1)

具有递归

<script src="http://underscorejs.org/underscore-min.js"></script>

使用迭代方法(使用堆栈)

# 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)

按词典顺序排序

# 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)

答案 23 :(得分:-1)

这是一个简单直接的递归实现;

RecyclerView

答案 24 :(得分:-1)

导入迭代工具 def minion_game(s):

vow ="aeiou"
lsword=[]
ta=[]
for a in range(1,len(s)+1):
    t=list(itertools.permutations(s,a))
    lsword.append(t)

for i in range(0,len(lsword)):
    for xa in lsword[i]:
        if vow.startswith(xa):
            ta.append("".join(xa))

print(ta)

minion_game("banana")