思路:回溯
遍历数组,遇到一个数没被用过,就添加到路径里,接着向下搜索;
当搜索深度depth等于数组大小,结束,把路径添加到结果里
设置数组 used记录每个数字是否被选过,初始化的时候都为 false ,当我们选定一个数的时候,就将这个数组的相应位置设置为 true
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
def dfs(depth,used):
if depth==l:
res.append(path[:])
return
for i in range(l):
if not used[i]:
used[i]=True
path.append(nums[i])
dfs(depth+1,used)
#回撤操作
used[i]=False
path.pop()
l=len(nums)
used = [False for _ in range(l)]
res=[]
path=[]
dfs(0,used)
return res
优化空间:不使用额外空间used数组记录状态
将题目给定的 n 个数的数组nums[]
划分成左右两个部分,左边的表示已经填过的数,右边表示待填的数,我们在递归搜索的时候只要动态维护这个数组即可。
具体来说,假设我们已经填到第depth
个位置,那么 nums[]
数组中[0,depth−1]
是已填过的数的集合,[depth,n−1]
是待填的数的集合。
我们肯定是尝试用[depth,n−1]
里的索引为i
的数去填第depth
个数,那么填完以后我们将第 i
个数和第 depth
个数交换,即可满足要求,回溯的时候交换回来即能完成撤销操作。
那么一个数组目前为 [8, 9 | 2, 5, 10] 这样的状态,分隔符区分了左右两个部分。假设这个位置我们要填 10 这个数,为了维护数组,我们将 2 和 10 交换,变为 [8, 9, 10 | 2, 5] 。
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
def dfs(depth):
if depth == l:
# 所有数都填完了
res.append(nums[:])
for i in range(depth, l):
nums[i], nums[depth] = nums[depth], nums[i]
dfs(depth + 1)
# 撤销操作
nums[i], nums[depth] = nums[depth], nums[i]
l=len(nums)
res=[]
dfs(0)
return res