给定一个不含重复数字的数组 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]]
提示
1 <= nums.length <= 6
2. -10 <= nums[i] <= 10
3. nums 中的所有整数 互不相同
首先我们要明白排列的概念以及和组合的区别
所谓排列,就是指从给定个数的元素中取出指定个数的元素进行排序。组合则是指从给定个数的元素中仅仅取出指定个数的元素,不考虑排序。
这里我画了一下示例1的图示,如果对排列有不理解的可以看这张图理解
可以看到在每一层递归中我们都会选择一个数字,当选择的数字到达3个后我们把当前的排列加入答案中,然后通过逐级回溯到上层递归去寻找其他的排列,下面我们看代码
首先在主函数中我们要定义一个bool类型的容器,这个容器的作用是用于在递归的时候去跳过当前我们已经在之前选中的数字,结合上面的图我们可以看到:
在第一层中我们选中了1,下一层中就只有2,3可以选择了
同样,如果第一层选中的是2,下一层中就只有1,3可以选择了
如果第一层选中的是3,下一层中就只有1,2可以选择了
因此我们想要知道在当前递归之前我们已经选中了哪些数字,就需要定义一个bool类型的数组或容器,用来标识数组中哪些数字已经被使用了,而这个bool类型的数组或容器大小与题目所给的nums数组是一致的
class Solution {
public:
vector<vector<int>> ans;
vector<int> temp;
int n;
vector<vector<int>> permute(vector<int>& nums) {
n = nums.size();
vector<bool> record(n, false);
dfs(0, nums, record);
return ans;
}
};
然后进入dfs函数,出口条件就是递归深度等于了数组长度的时候,同时也是选中了所有的数字的时候,把当前的排列加入答案中,然后回溯到上一层
void dfs(int u, vector<int>& nums, vector<bool>& record) {
if(u == n) {
ans.push_back(temp);
return;
}
}
然后要注意在每一层中,我们都遍历数组nums,在循环中判断如果当前nums[i]在record数组中还没有使用过,也就是!record[i]为真时,则把当前nums[i]加入排列中
然后就是一个回溯的写法,进入下一层之间把record[i]置成true表示在下一层递归中当前数字已经使用了,在下一层递归结束后把record[i]又置成false,回溯到进入下一层递归前的状态
void dfs(int u, vector<int>& nums, vector<bool>& record) {
if(u == n) {
ans.push_back(temp);
return;
}
for(int i = 0; i < n; i++) {
if(!record[i]) {
record[i] = true;
temp.push_back(nums[i]);
dfs(u + 1, nums, record);
temp.pop_back();
record[i] = false;
}
}
}
然后把代码整合起来
完整代码:
class Solution {
public:
vector<vector<int>> ans;
vector<int> temp;
int n;
void dfs(int u, vector<int>& nums, vector<bool>& record) {
if(u == n) {
ans.push_back(temp);
return;
}
for(int i = 0; i < n; i++) {
if(!record[i]) {
record[i] = true;
temp.push_back(nums[i]);
dfs(u + 1, nums, record);
temp.pop_back();
record[i] = false;
}
}
}
vector<vector<int>> permute(vector<int>& nums) {
n = nums.size();
vector<bool> record(n, false);
dfs(0, nums, record);
return ans;
}
};