如何生成列表的所有排列?

Posted

技术标签:

【中文标题】如何生成列表的所有排列?【英文标题】:How to generate all permutations of a list? 【发布时间】:2010-09-11 09:22:30 【问题描述】:

如何在 Python 中生成列表的所有排列,而与列表中元素的类型无关?

例如:

permutations([])
[]

permutations([1])
[1]

permutations([1, 2])
[1, 2]
[2, 1]

permutations([1, 2, 3])
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]

【问题讨论】:

我同意递归,接受的答案 - 今天。然而,这仍然是一个巨大的计算机科学问题。公认的答案以指数复杂度解决了这个问题 (2^N N=len(list)) 在多项式时间内解决它(或证明你不能):) 请参阅“旅行推销员问题” @FlipMcF 很难在多项式时间内“解决”它,因为它需要阶乘时间来枚举输出......所以,不,这是不可能的。 @FlipMcF: 不,这不是真的:a) 只是为了找到 最佳 解决方案,而不是 足够好 解决方案,这对于现实世界的目的和b)我们不需要扩展搜索空间中的所有节点,即所有排列;这就是heuristic algorithms like A* 【参考方案1】:
def permutate(l):
    for i, x in enumerate(l):
        for y in l[i + 1:]:
            yield x, y


if __name__ == '__main__':
    print(list(permutate(list('abcd'))))
    print(list(permutate([1, 2, 3, 4])))

#[('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
#[(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]

【讨论】:

美观又简单!【参考方案2】:

我的 Python 解决方案:

def permutes(input,offset):
    if( len(input) == offset ):
        return [''.join(input)]

    result=[]        
    for i in range( offset, len(input) ):
         input[offset], input[i] = input[i], input[offset]
         result = result + permutes(input,offset+1)
         input[offset], input[i] = input[i], input[offset]
    return result

# input is a "string"
# return value is a list of strings
def permutations(input):
    return permutes( list(input), 0 )

# Main Program
print( permutations("wxyz") )

【讨论】:

【参考方案3】:
def permutation(word, first_char=None):
    if word == None or len(word) == 0: return []
    if len(word) == 1: return [word]

    result = []
    first_char = word[0]
    for sub_word in permutation(word[1:], first_char):
        result += insert(first_char, sub_word)
    return sorted(result)

def insert(ch, sub_word):
    arr = [ch + sub_word]
    for i in range(len(sub_word)):
        arr.append(sub_word[i:] + ch + sub_word[:i])
    return arr


assert permutation(None) == []
assert permutation('') == []
assert permutation('1')  == ['1']
assert permutation('12') == ['12', '21']

print permutation('abc')

输出:['abc', 'acb', 'bac', 'bca', 'cab', 'cba']

【讨论】:

【参考方案4】:

使用Counter

from collections import Counter

def permutations(nums):
    ans = [[]]
    cache = Counter(nums)

    for idx, x in enumerate(nums):
        result = []
        for items in ans:
            cache1 = Counter(items)
            for id, n in enumerate(nums):
                if cache[n] != cache1[n] and items + [n] not in result:
                    result.append(items + [n])

        ans = result
    return ans
permutations([1, 2, 2])
> [[1, 2, 2], [2, 1, 2], [2, 2, 1]]

【讨论】:

【参考方案5】:
def permuteArray (arr):

    arraySize = len(arr)

    permutedList = []

    if arraySize == 1:
        return [arr]

    i = 0

    for item in arr:

        for elem in permuteArray(arr[:i] + arr[i + 1:]):
            permutedList.append([item] + elem)

        i = i + 1    

    return permutedList

我不打算在新产品线中穷尽所有可能性,以使其有些独特。

【讨论】:

【参考方案6】:
from typing import List
import time, random

def measure_time(func):
    def wrapper_time(*args, **kwargs):
        start_time = time.perf_counter()
        res = func(*args, **kwargs)
        end_time = time.perf_counter()
        return res, end_time - start_time

    return wrapper_time


class Solution:
    def permute(self, nums: List[int], method: int = 1) -> List[List[int]]:
        perms = []
        perm = []
        if method == 1:
            _, time_perm = self._permute_recur(nums, 0, len(nums) - 1, perms)
        elif method == 2:
            _, time_perm = self._permute_recur_agian(nums, perm, perms)
            print(perm)
        return perms, time_perm

    @measure_time
    def _permute_recur(self, nums: List[int], l: int, r: int, perms: List[List[int]]):
        # base case
        if l == r:
            perms.append(nums.copy())

        for i in range(l, r + 1):
            nums[l], nums[i] = nums[i], nums[l]
            self._permute_recur(nums, l + 1, r , perms)
            nums[l], nums[i] = nums[i], nums[l]

    @measure_time
    def _permute_recur_agian(self, nums: List[int], perm: List[int], perms_list: List[List[int]]):
        """
        The idea is similar to nestedForLoops visualized as a recursion tree.
        """
        if nums:
            for i in range(len(nums)):
                # perm.append(nums[i])  mistake, perm will be filled with all nums's elements.
                # Method1 perm_copy = copy.deepcopy(perm)
                # Method2 add in the parameter list using + (not in place)
                # caveat: list.append is in-place , which is useful for operating on global element perms_list
                # Note that:
                # perms_list pass by reference. shallow copy
                # perm + [nums[i]] pass by value instead of reference.
                self._permute_recur_agian(nums[:i] + nums[i+1:], perm + [nums[i]], perms_list)
        else:
            # Arrive at the last loop, i.e. leaf of the recursion tree.
            perms_list.append(perm)



if __name__ == "__main__":
    array = [random.randint(-10, 10) for _ in range(3)]
    sol = Solution()
    # perms, time_perm = sol.permute(array, 1)
    perms2, time_perm2 = sol.permute(array, 2)
    print(perms2)
    # print(perms, perms2)
    # print(time_perm, time_perm2)
```

【讨论】:

一些解释会改善这个答案。【参考方案7】:

如果有人喜欢这种丑陋的单线(虽然仅适用于字符串):

def p(a):
    return a if len(a) == 1 else [[a[i], *j] for i in range(len(a)) for j in p(a[:i] + a[i + 1:])]

【讨论】:

【参考方案8】:

使用递归求解,遍历元素,获取第 i 个元素,然后问自己:'其余元素的排列是什么',直到没有元素为止。

我在这里解释了解决方案:https://www.youtube.com/watch?v=_7GE7psS2b4

class Solution:
    def permute(self,nums:List[int])->List[List[int]]:
        res=[]
        def dfs(nums,path):
            if len(nums)==0:
                res.append(path)
            for i in range(len(nums)):
                dfs(nums[:i]+nums[i+1:],path+[nums[i]])
        dfs(nums,[])
        return res

【讨论】:

【参考方案9】:

对于 Python,我们可以使用 itertools 并导入排列和组合来解决您的问题

from itertools import product, permutations
A = ([1,2,3])
print (list(permutations(sorted(A),2)))

【讨论】:

以上是关于如何生成列表的所有排列?的主要内容,如果未能解决你的问题,请参考以下文章

生成真/假的所有长度-n 排列?

如何从所有排列中生成所有可能的组合?

R如何排列数据帧的所有行,以便在列表中返回所有可能的行组合?

如何迭代 Rust 中序列的所有唯一排列?

如何生成包含连续数字和字母的混合列表?

如何生成多重集的所有排列?