排列 - DFS 和回溯 - 需要帮助理解展开和回溯
Posted
技术标签:
【中文标题】排列 - DFS 和回溯 - 需要帮助理解展开和回溯【英文标题】:Permutation- DFS and backtracking- need help in understanding unwinding and backtracking 【发布时间】:2019-02-19 19:14:02 【问题描述】:以下代码用于实现 Ints 数组的排列。我无法理解这里的回溯是如何完成的——尤其是在我打印[1, 2, 3]
之后,我如何返回并打印[1, 3, 2]
——path.removeLast()
究竟是如何工作的?
func permute(_ nums: [Int]) -> [[Int]]
var res = [[Int]]()
var path = [Int]()
var isVisited = [Bool](repeating: false, count: nums.count)
var counter = 0
dfs(&res, &path, &isVisited, nums)
return res
private func dfs(_ res: inout [[Int]], _ path: inout [Int], _ isVisited: inout [Bool], _ nums: [Int])
guard path.count != nums.count else
res.append(path)
return
for (i, num) in nums.enumerated() where !isVisited[i]
path.append(num)
isVisited[i] = true
dfs(&res, &path, &isVisited, nums)
isVisited[i] = false
path.removeLast()
【问题讨论】:
【参考方案1】:有时通过一个例子来理解回溯是最容易的。取数组 [1,2,3],然后使用您的方法执行以下操作:
Before removing: 1
Before removing: 1 2
Before removing: 1 2 3
After removing: 1 2
After removing: 1
Before removing: 1 3
Before removing: 1 3 2
After removing: 1 3
After removing: 1
After removing:
Before removing: 2
Before removing: 2 1
Before removing: 2 1 3
After removing: 2 1
After removing: 2
Before removing: 2 3
Before removing: 2 3 1
After removing: 2 3
After removing: 2
After removing:
Before removing: 3
Before removing: 3 1
Before removing: 3 1 2
After removing: 3 1
After removing: 3
Before removing: 3 2
Before removing: 3 2 1
After removing: 3 2
After removing: 3
After removing:
实际上,您所做的是为每个排列生成所有可能的子序列,然后删除它们(因此删除最后一个),直到您返回一个空列表。如果您为您提供的代码绘制递归树,您将有 31 个节点(上面的每一行一个节点)。我们能做得更好吗?是的。对于同一示例,请考虑以下树:
(此处使用字符而不是整数的类似树的更漂亮版本:Permutation of string using backtracking algorithm)
一个很大的改进。树中只有 10 个节点,树中的最后一层具有所有排列。这可以使用回溯来完成,并且是一个更容易理解的示例。您所做的只是交换节点,而不是为每个排列生成所有可能的子序列。可以在此处找到第二种更好方法的 Swift 实现:https://leetcode.com/problems/permutations/discuss/229627/Swift
【讨论】:
以上是关于排列 - DFS 和回溯 - 需要帮助理解展开和回溯的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode 526 优美的排列[dfs 回溯] HERODING的LeetCode之路