题目描述
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以按任意顺序返回答案。
示例 1:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
分析
与组合问题一样,排列问题同样可以看作是一棵树,于是就有DFS遍历;显然也要用递归算法。具体思路是让数组中的元素"轮流当老大":
1.每次递归,只需要把轮到的元素放到第一位(该元素当老大);
2.排列的结果是老大+所有小弟的全排列;
3.对于同一层:由于老大是不同的,因此排列结果不会有重复;
4.对于下一层:老大坐稳后,第二个位置就变成新的老大;小弟们再次轮流选坐;
代码版本一
按照最直观的思路,每一层把老大推进"排位切片permu",剩下的小弟传入下一层迭代;
func permute(nums []int) (res [][]int) {
dfs := func([]int, []int) {}
dfs = func(nums []int, permu []int) { // permu为排位切片
if len(nums) == 0 {
res = append(res, append([]int{}, permu...))
return
}
for i, num := range nums {
permu = append(permu, num)
dfs(append(append([]int{}, nums[:i]...), nums[i+1:]...), permu)
permu = permu[:len(permu)-1]
}
}
dfs(nums, []int{})
return
}
时间复杂度 O(n!);
代码版本二
版本一的每一层dfs函数都要为其局部变量 nums 和 permu 开辟内存;空间复杂度较高。
其实轮流当老大只需要把元素位置跟第一位的元素交换即可;因为当前层级只关心谁是老大,不用关心其余小弟们的顺序。同时我们也不需要另外一个排列切片permu,整个递归过程都在nums上进行;
func permute(nums []int) (res [][]int) {
dfs := func(int) {}
n := len(nums)
dfs = func(idx int) { // idx 代表排第几位
if idx == n {
res = append(res, append([]int(nil), nums...))
return
}
for i := idx; i < n; i++ { // 本层轮流当老大
nums[i], nums[idx] = nums[idx], nums[i]
dfs(idx + 1)
nums[i], nums[idx] = nums[idx], nums[i]
}
}
dfs(0)
return
}
在每一次完全排列完之后,代码还会进入下一层循环以判断边界(即是否到达n),复杂度变为了 O(n*n!) ;
但空间复杂度大大降低了,因此运行效率可能会更高。