Python非递归排列

时间:2016-08-17 04:03:08

标签: python algorithm permutation

是否有人理解以下迭代算法来生成数字列表的所有排列?

我不理解while len(stack)循环中的逻辑。有人可以解释它是如何工作的吗?

# Non-Recursion
@param nums: A list of Integers.
@return: A list of permutations.

def permute(self, nums):
    if nums is None:
        return []
    nums = sorted(nums)
    permutation = []
    stack = [-1]
    permutations = []
    while len(stack):
        index = stack.pop()
        index += 1
        while index < len(nums):
            if nums[index] not in permutation:
                break
            index += 1
        else:
            if len(permutation):
                permutation.pop()
            continue

        stack.append(index)
        stack.append(-1)
        permutation.append(nums[index])
        if len(permutation) == len(nums):
            permutations.append(list(permutation))
    return permutations

我只是想了解上面的代码。

2 个答案:

答案 0 :(得分:2)

正如您的问题的评论部分所述,调试可能提供了一种有用的方法来理解代码的作用。但是,让我提供一个关于代码功能的高级视角。

首先,尽管没有对函数置换的递归调用,但是您提供的代码实际上是递归的,因为它只是保留自己的堆栈,而不是使用操作系统内存管理器提供的代码。具体来说,变量堆栈保留了“递归数据”,可以说是从一个递归调用传递到另一个递归调用。你可以,也许应该考虑 permute 函数中外部while循环的每次迭代作为递归调用。如果你这样做,你会看到外部while循环有助于“递归地”以深度优先的方式遍历 nums 的每个排列。

注意到这一点,很容易弄清楚每个“递归调用”的作用。基本上,变量置换保持 nums 的当前排列,这是在循环进行时形成的。变量排列存储找到的 nums 的所有排列。正如您所看到的,只有当 len(置换)等于 len(nums)时才会更新置换,这可以被视为基本情况使用自定义堆栈实现的重复关系。最后,内部while循环基本上选择 nums 中的哪个元素添加到正在形成的当前排列(即存储在变量置换中)。

这就是它,真的。根据建议,您可以使用调试器找出与维护堆栈相关的线路上正在完成的操作。最后,请允许我重复一遍,我个人不认为这种实现是非递归的。事实恰恰相反,这种递归解决方案不是使用操作系统提供的抽象,而是保留自己的堆栈。为了更好地理解正确的非递归解决方案,您可以观察到下面提供的找到n th Fibonacci数的问题的递归和迭代解决方案的差异。正如您所看到的,非递归解决方案不会保留堆栈,而是将问题划分为较小的实例(递归),而是从较小的解决方案构建解决方案。 (动态编程)

def recursive_fib(n):
    if n == 0:
        return 0
    return recursive_fib(n-1) - recursive_fib(n-2)

def iterative_fib(n):
    f_0 = 0
    f_1 = 1
    for i in range(3, n):
        f_2 = f_1 + f_0
        f_0 = f_1
        f_1 = f_2
    return f_1

答案 1 :(得分:0)

@ilim的答案是正确的,应该是接受的答案,但我只是想添加另一个不适合作为评论的观点。虽然我想你正在研究这个算法作为练习,但应该指出,根据列表的大小,更好的方法可以是用户itertools的{​​{1}}函数:< / p>

permutations()

在我的机器上使用11项(39m排列)的列表进行测试,使用print [x for x in itertools.permutations([1, 2, 3])] 需要1.7秒,但使用上面的自定义解决方案需要76秒。但请注意,如果有12个项目(479m排列),itertools.permutations(x)解决方案会因内存错误而崩溃。如果您需要有效地生成这种大小的排列,您可能最好放弃本机代码。