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

2025-01-17 09:23:00
admin
原创
79
摘要:问题描述:我有一个字符串。我想通过改变其中字符的顺序来生成该字符串的所有排列。例如:x='stack' 我想要的是这样的列表,l=['stack','satck','sackt'.......] 目前,我正在迭代字符串的列表转换,随机挑选 2 个字母并将它们转置以形成一个新字符串,并将其添加到 l 的集合转换...

问题描述:

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

x='stack'

我想要的是这样的列表,

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

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


解决方案 1:

itertools 模块有一个很有用的方法,叫做 permutations()。文档中说:

itertools.permutations(iterable[, r])

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

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

排列按字典顺序发出。因此,如果输入的可迭代对象已排序,则排列元组将按排序顺序生成。

不过你必须将排列后的字母连接成字符串。

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

['堆栈','stakc','stcak','stcka','stkac','stkca','satck','satkc','sactk','sackt','saktc','sakct',' sctak'、'sctka'、'scatk'、'scat'、 'sckta'、'sckat'、'sktac'、'sktca'、'skatc'、'skact'、'skcta'、'skcat'、'tsack'、'tsakc'、'tscak'、'tscka'、'tskac ', 'tskca', 'tasck', 'taskc', 'tacsk', '大头钉', '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']

如果您发现自己被重复项所困扰,请尝试将数据放入没有重复项的结构中,例如set

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

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

解决方案 2:

无需太多代码即可获得所有 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)

解决方案 3:

这是基于反向跟踪的另一种使用最少代码进行字符串排列的方法。我们基本上创建一个循环,然后每次交换两个字符,在循环内部我们将进行递归。注意,我们只在索引器达到字符串长度时才打印。示例:ABC i 为我们的起点,递归参数 j 为我们的循环

这里有一个视觉帮助,说明它是如何从左到右从上到下的(排列顺序)

在此处输入图片描述

代码:

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)

解决方案 4:

itertools.permutations很好,但它不能很好地处理包含重复元素的序列。这是因为它在内部对序列索引进行了置换,而忽略了序列项的值。

当然,可以itertools.permutations通过集合过滤输出以消除重复项,但生成这些重复项仍然会浪费时间,并且如果基础序列中有多个重复元素,则会有很多重复项。此外,使用集合保存结果会浪费 RAM,从而抵消使用迭代器的好处。

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

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

解决方案 5:

Stack Overflow 用户已经发布了一些很好的解决方案,但我想展示另一个解决方案。我发现这个更直观

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

字符串中字符的排列 = char + 排列(字符串 - 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, "", 1))]
    return permutation_list

解决方案 6:

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

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

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

    return set(recursive_perms)

解决方案 7:

这是另一种与 @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

对于任意字符串“dadffddxcf”,排列库需要 1.1336 秒,此实现需要 9.125 秒,@Adriano 和 @illerucis 版本需要 16.357 秒。当然,您仍然可以对其进行优化。

解决方案 8:

这里有一个稍微改进的illerucis代码版本,用于返回具有不同字符的字符串的所有排列列表s(不一定按字典顺序排列),而不使用 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

解决方案 9:

请参阅itertools.combinationsitertools.permutations

解决方案 10:

你为什么不简单地做:

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]

解决方案 11:

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

解决方案 12:

所有可能的单词与堆栈

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

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

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

排列按字典顺序发出。因此,如果输入的可迭代对象已排序,则排列元组将按排序顺序生成。

元素的唯一性取决于其位置,而不是其值。因此,如果输入元素是唯一的,则每次排列中都不会出现重复值。

解决方案 13:

采用递归方法。

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

解决方案 14:

这是一个递归解决方案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")

解决方案 15:

又一个创新和递归解决方案。其思想是选择一个字母作为枢轴,然后创建一个单词。

def find_premutations(alphabet):
    
    words = []
    word =''
    
    def premute(new_word, alphabet):
        if not alphabet:
            words.append(word)
        else:
            for i in range(len(alphabet)):
                premute(new_word=word + alphabet[i], alphabet=alphabet[0:i] + alphabet[i+1:])

    premute(word, alphabet)
    return words


# let us try it with 'abc'
a = 'abc'
find_premutations(a)

输出:

abc
acb
bac
bca
cab
cba

解决方案 16:

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

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)

我觉得还不错!

解决方案 17:

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

解决方案 18:

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

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

解决方案 19:

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

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

解决方案 20:

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

这是使用递归生成排列的一种方法,您可以通过将字符串“a”、“ab”和“abc”作为输入轻松理解代码。

通过这个你可以得到所有 N! 个排列,并且没有重复。

解决方案 21:

每个人都喜欢自己代码的味道。这里只分享一个我认为最简单的:

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

解决方案 22:

该程序不会消除重复,但我认为这是最有效的方法之一:

s=raw_input("Enter a string: ")
print "Permutations :
",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

解决方案 23:

使用递归

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

按字典顺序排序

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

解决方案 24:

这段代码对我来说很有意义。逻辑是循环遍历所有字符,提取第 i 个字符,对其他元素执行排列,并将第 i 个字符附加到开头。

如果要求我手动获取字符串 ABC 的所有排列。我将首先检查元素 A 的所有组合:

  • AB

  • BC

然后元素 B 的所有组合:

  • 加拿大

  • 加拿大

然后元素 C 的所有组合:

  • 出租车

  • 加拿大职业篮球联赛

def permute(s: str):
  n = len(s)
  if n == 1: return [s]
  if n == 2:
    return [s[0]+s[1], s[1]+s[0]]

  permutations = []
  for i in range(0, n):
    current = s[i]
    others = s[:i] + s[i+1:]

    otherPermutations = permute(others)
    for op in otherPermutations:
      permutations.append(current + op)

  return permutations

解决方案 25:

只是为了整理一下机器对重复情况的回答:因为集合是一个无序的数据结构,所以它不保留顺序。要生成以输入单词开头的列表:

from itertools import permutations

x = "stacks"
perms = list(set([''.join(char) for char in permutations(x)]))
perms.insert(0, perms.pop(perms.index(x)))
perms

解决方案 26:

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

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)

解决方案 27:

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)

解决方案 28:

标准库中的模块itertools有一个名为的函数permutations

import itertools

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")
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1590  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1361  
  信创产品在政府采购中的占比分析随着信息技术的飞速发展以及国家对信息安全重视程度的不断提高,信创产业应运而生并迅速崛起。信创,即信息技术应用创新,旨在实现信息技术领域的自主可控,减少对国外技术的依赖,保障国家信息安全。政府采购作为推动信创产业发展的重要力量,其对信创产品的采购占比情况备受关注。这不仅关系到信创产业的发展前...
信创和国产化的区别   18  
  信创,即信息技术应用创新产业,旨在实现信息技术领域的自主可控,摆脱对国外技术的依赖。近年来,国货国用信创发展势头迅猛,在诸多领域取得了显著成果。这一发展趋势对科技创新产生了深远的推动作用,不仅提升了我国在信息技术领域的自主创新能力,还为经济社会的数字化转型提供了坚实支撑。信创推动核心技术突破信创产业的发展促使企业和科研...
信创工作   18  
  信创技术,即信息技术应用创新产业,旨在实现信息技术领域的自主可控与安全可靠。近年来,信创技术发展迅猛,对中小企业产生了深远的影响,带来了诸多不可忽视的价值。在数字化转型的浪潮中,中小企业面临着激烈的市场竞争和复杂多变的环境,信创技术的出现为它们提供了新的发展机遇和支撑。信创技术对中小企业的影响技术架构变革信创技术促使中...
信创国产化   19  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用