没有 itertools 的两个值的排列(使用递归!)

Posted

技术标签:

【中文标题】没有 itertools 的两个值的排列(使用递归!)【英文标题】:Permutations without itertools for two values (using recursion!) 【发布时间】:2021-08-01 22:10:29 【问题描述】:

***,我再次寻求您的帮助。

我知道还有其他关于此的主题,但我会解释是什么让我的作业与众不同。

基本上,我的函数会得到一个 0 和 1 的列表,并返回字符串的所有可能顺序。例如对于“0111”,我们将得到“0111”、“1011”、“1101”、“1110”。

这是我的代码:

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

    lst = []

    for j in range(len(string)):
        remaining_elements = ''.join([string[i] for i in range(len(string)) if i != j])
        mini_perm = permutations(remaining_elements)

        for perm in mini_perm:
            new_str = string[j] + perm
            if new_str not in lst:
                lst.append(new_str)

    return lst

问题是当我运行像“000000000011”这样的字符串时,需要很长时间来处理。应该有一种更有效的方法来做到这一点,因为它只有两个数字。所以我不应该使用索引?

如果您能找到更有效的说法,请帮助我。

(我可以使用循环,但也必须使用递归!)

【问题讨论】:

您可以随时查看itertools 源代码以了解它是如何实现的,如果您不想使用该模块,请执行类似的操作。 docs.python.org/3/library/itertools.html#itertools.permutations @PacketLoss itertools permutations 函数比我写的自定义版本还要慢,因为它会重复相似的对象。这在基本的 Python 中应该是可能的——递归、for、循环,没有 OOP。 您的示例“000000000011”是否应该返回01 and 10 @PacketLoss 它应该返回“000000000011”、“000000000101”、“000000001001”等。 【参考方案1】:

下面是一个使用更有效的递归创建排列的示例:

def permute(string):
    string = list(string)
    n = len(string)

    # Base conditions
    # If length is 0 or 1, there is only 1 permutation
    if n in [0, 1]:
        return [string]

    # If length is 2, then there are only two permutations
    # Example: [1,2] and [2,1]
    if n == 2:
        return [string, string[::-1]]

    res = []
    # For every number in array, choose 1 number and permute the remaining
    # by calling permute recursively
    for i in range(n):
        permutations = permute(string[:i] + string[i+1:])
        for p in permutations:
            res.append([''.join(str(n) for n in [string[i]] + p)])

    return res

这也适用于permute('000000000011') - 希望对您有所帮助!

【讨论】:

【参考方案2】:

您还可以将collections.Counter 与递归生成器函数一起使用:

from collections import Counter
def permute(d):
   counts = Counter(d)
   def get_permuations(c, s = []):
     if len(s) == sum(counts.values()):
        yield ''.join(s)
     else:
        for a, b in c.items():
           for i in range(1, b+1):
              yield from get_permuations(**c, a:b - i, s+([a]*i))
   return list(set(get_permuations(counts)))

print(permute("0111"))
print(permute("000000000011"))

输出:

['0111', '1110', '1101', '1011']
['010000100000', '100000000001', '010000001000', '000000100001', '011000000000', '100000000010', '001001000000', '000000011000', '100000001000', '100000100000', '100001000000', '001000100000', '100010000000', '000000001100', '000100000100', '010010000000', '000000000011', '000000100010', '101000000000', '110000000000', '100000010000', '000100001000', '000001001000', '000000000101', '000000100100', '010000000001', '001000000100', '001000000010', '000110000000', '000011000000', '000001100000', '000000110000', '001000000001', '000010001000', '000100100000', '000001000001', '000010000001', '001100000000', '000100000001', '001000001000', '010000000100', '010000010000', '000000010001', '001000010000', '010001000000', '100000000100', '100100000000', '000000001001', '010100000000', '000010100000', '010000000010', '000000001010', '000010000100', '001010000000', '000000010010', '000001000010', '000100000010', '000101000000', '000000010100', '000100010000', '000000000110', '000001000100', '000010010000', '000000101000', '000001010000', '000010000010']

【讨论】:

【参考方案3】:

发布某人给我的答案。感谢您的回复!:

def permutations(zeroes, ones, lst, perm):
    if zeroes == 0 and ones == 0:
        lst.append(perm)
        return
    elif zeroes < 0 or ones < 0:
        return
    
    permutations(zeroes - 1, ones, lst, perm + '0')
    permutations(zeroes, ones - 1, lst, perm + '1')

【讨论】:

以上是关于没有 itertools 的两个值的排列(使用递归!)的主要内容,如果未能解决你的问题,请参考以下文章

具有唯一值的排列

算法之使用递归求解全排列

Python3 - 排列组合的迭代

使用python的值列表中随机值的所有排列

用itertools解决无序排列组合问题

itertools 排列组合