46. 全排列 Medium
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
示例 1:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例 2:
输入:nums = [0,1]
输出:[[0,1],[1,0]]
示例 3:
输入:nums = [1]
输出:[[1]]
解题思路
输入:一个没有重复数字的整数数组 nums
。
输出:返回所有可能的排列结果。
这道题属于 排列型回溯 问题。
- 我们需要在每个位置上选择一个数字,保证每个数字只出现一次。
- 用一个
path
保存当前排列的结果。 - 用一个集合
s
记录还剩下哪些数字可以选。 - 当
path
的长度等于nums
的长度时,说明当前路径是一个完整的排列,就把它保存到答案中。 - 每次选择完一个数字,就将它从可选集合
s
中删除,然后递归到下一层。 - 回溯时,要撤销选择,把数字从
path
中移除。
回溯三问
当前操作?
- 在当前位置
i
(表示排列中已经选了多少个数字),从还没被选过的数字集合s
中,依次尝试选择一个数字x
放入当前排列path
中。 - 也就是把数字
x
放到path
里,表示“我选择了这个数字”。
- 在当前位置
子问题?
- 选择了数字
x
之后,需要继续递归构造排列的剩余部分。 - 也就是在集合
s - {x}
里继续选择下一个数字。
- 选择了数字
下一个子问题?
- 下一步递归就是调用
dfs(i + 1, s - {x})
,表示继续在剩下的数字中选择,直到排列长度等于n
。
- 下一步递归就是调用
剪枝条件
- 只有当数字
x
还存在于集合s
中时,才可以选择它。 - 当排列长度达到
n
时,就把当前排列加入答案。 - 由于题目保证数字没有重复,所以不需要对结果进行去重。
代码实现
python
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
ans = [] # 用来存放所有排列结果
path = [] # 用来存放当前路径上的数字(当前排列)
n = len(nums) # 数组长度
def dfs(i, s):
"""
i: 当前递归层数,表示排列中已经选了多少个数字
s: 当前还剩下哪些数字可以选(集合)
"""
if i == n:
# 当排列长度达到数组长度时,说明当前路径是一个完整排列
ans.append(path.copy())
return
for x in nums:
# 只有当数字 x 还没被选过(存在于 s 中)时才选它
if x in s:
path.append(x) # 选择数字 x
dfs(i + 1, s - {x}) # 递归下一层,集合 s 减去已选数字 x
path.pop() # 回溯,撤销选择,尝试别的数字
dfs(0, set(nums)) # 从第0层开始,所有数字都可以选
return ans
javascript
/**
* @param {number[]} nums
* @return {number[][]}
*/
var permute = function(nums) {
const ans = []; // 存放所有的排列结果
const path = []; // 当前排列的路径
const unUsed = new Set(nums); // 记录还没有被选择的数字(用 Set 保证查找快)
/**
* @param {number} i 当前递归的层数(表示当前排列中已经选择了多少个数字)
* @param {Set} s 当前剩余的可选数字集合
*/
function dfs(i, s) {
// 如果已经选够了 nums.length 个数字,说明找到了一种排列
if (i === nums.length) {
ans.push([...path]); // 把当前排列保存到结果数组中(深拷贝)
return;
}
// 枚举所有剩余的数字
for (let x of nums) {
if (s.has(x)) { // 只有没有被选过的数字才能选择
path.push(x); // 选择当前数字
s.delete(x); // 标记当前数字为“已使用”
dfs(i + 1, s); // 递归到下一层,继续选择数字
// 回溯:撤销选择
s.add(x); // 恢复当前数字为“未使用”
path.pop(); // 移除当前数字
}
}
}
dfs(0, unUsed); // 从第0层开始,初始可选数字是所有的数字
return ans; // 返回所有的排列结果
};
复杂度分析
时间复杂度:O(n * n!)
空间复杂度:O(n * n!)