通过回溯了解排列

Understanding permutations with backtracking

我正在尝试弄清楚以下回溯解决方案如何生成以列表形式给出的所有整数排列:

def permutations(arr):
    res = []
    backtrack(arr, [], set(), res)
    print(res)

def backtrack(arr, temp, visited, res):
    if len(temp) == len(arr):
        res.append(temp[:])
    else:
        for num in arr:
            if num in visited: continue
            visited.add(num)
            temp.append(num)
            backtrack(arr, temp, visited, res)
            visited.remove(num)
            temp.pop()

正在执行以下操作:

permutations([1, 2, 3])

结果符合预期:

[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]

我不明白的是循环结束时的 temp.pop() 调用。 我知道 pop() 会丢弃列表的最后一个元素,但为什么这里有必要?

如果有人能向我解释一下,我将不胜感激。

这是必要的,因为在下一次迭代中,该函数将再次 append 一个元素,因此如果您事先没有 pop ,列表的大小将继续增长。由于 backtrack 仅在 temp 的长度等于原始 arr 的长度时才添加结果,因此它不会添加超出第一个排列 [1, 2, 3] 的任何内容(因为从那里开始, temp 列表不断增加)。

我们可以删除该行 (temp.pop()) 并查看结果:

[[1, 2, 3]]

现在,如果我们还更改每当 len(temp) >= len(arr) 时添加结果,那么我们将看到 temp 的大小如何增长:

[[1, 2, 3], [1, 2, 3, 3], [1, 2, 3, 3, 2], [1, 2, 3, 3, 2, 3]]

我们在这里得到的结果较少,因为对于超出 [1, 2, 3] 的每个递归调用,都会立即复制 temp 列表,而不会到达 for 循环。