- 输入: [1,2,3]
- 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]
注意
- 不是组合问题,{1, 2}, {2, 1}是不一样的,因此不可以使用startIndex
- 也无关层之间去重,没有重复的元素。
- 需要考虑的是选完一个元素后,往下递归还能继续选择前面的元素。
used: 一个标记数组,记录哪些元素在当前路径中已经被使用了,即可解决问题3

代码
cpp
class Solution {
private:
vector<vector<int>> result;
vector<int> path;
// 核心回溯函数
// nums: 原始数组
// used: 一个标记数组,记录哪些元素在当前路径中已经被使用了
void backtracking(const vector<int>& nums, vector<bool>& used) {
// 1. 递归终止条件
// 当 path 的长度等于 nums 的长度时,说明找到了一个完整的全排列
if(path.size() == nums.size()){
result.push_back(path); // 将当前路径加入结果集
return; // 结束当前递归分支
}
// 2. 单层搜索逻辑
// 遍历 nums 中的每一个元素,尝试将其加入当前路径
for(int i = 0; i < nums.size(); i++){
// 如果 nums[i] 已经被使用过(在当前 path 中),则跳过,避免重复
if(used[i])
continue;
// 3. 处理节点(做选择)
used[i] = true; // 标记当前元素已使用
path.push_back(nums[i]); // 将当前元素加入路径
// 4. 递归调用
// 进入下一层决策树,继续填下一个位置的数
backtracking(nums, used);
// 5. 回溯(撤销选择)
// 当从递归返回时,说明当前分支已经探索完毕
// 需要将状态恢复到进入递归之前,以便尝试 for 循环中的下一个数字
used[i] = false; // 撤销标记
path.pop_back(); // 将当前元素移出路径
}
}
public:
vector<vector<int>> permute(vector<int>& nums) {
result.clear();
path.clear();
// 初始化 used 数组,大小与 nums 相同,初始全为 false
vector<bool> used(nums.size(), false);
backtracking(nums, used);
return result;
}
};
变形--全排列II
- 输入:nums = [1,1,2]
- 输出: [[1,1,2], [1,2,1], [2,1,1]]
- nums无序
这个就很简单了,加上层之间的去重就可以了,但是需要注意层去重有两种,有序和无序。
这里的nums无序只能使用unordered_set。单层循环逻辑里面加入去重即可。
cpp
unordered_set<int> uset;
for(int i = 0; i < nums.size(); i++){
if(used[i] || uset.find(nums[i]) != uset.end())
continue;
uset.insert(nums[i]);
used[i] = true; // 标记当前元素已使用
path.push_back(nums[i]); // 将当前元素加入路径
backtracking(nums, used);
used[i] = false; // 撤销标记
path.pop_back(); // 将当前元素移出路径
}