可以,按你现在这份代码,我帮你整理成"注释精简但够用"的版本。
class Solution {
public:
void backtracing(vector<int>& nums,
vector<bool>& used,
vector<vector<int>>& res,
vector<int>& path) {
// 1. 当前路径长度等于 nums 长度,说明得到一个完整排列
if (path.size() == nums.size()) {
res.push_back(path);
return;
}
// 2. 枚举当前这一层可以选择的数字
for (int i = 0; i < nums.size(); i++) {
// 当前数字已经使用过,跳过
if (used[i] == true) continue;
// 3. 做选择
path.push_back(nums[i]);
used[i] = true;
// 4. 递归选择下一个位置
backtracing(nums, used, res, path);
// 5. 回溯:撤销刚才的选择
path.pop_back();
used[i] = false;
}
}
vector<vector<int>> permute(vector<int>& nums) {
vector<bool> used(nums.size(), false); // 记录每个数字是否使用过
vector<vector<int>> res; // 保存所有排列结果
vector<int> path; // 保存当前排列
backtracing(nums, used, res, path);
return res;
}
};
这道题的思路总结
这道题使用的是 DFS + 回溯。
假设:
nums = [1,2,3]
我们需要不断选择数字放进 path:
[]
↓ 选1
[1]
↓ 选2
[1,2]
↓ 选3
[1,2,3]
当:
path.size() == nums.size()
说明一个排列完成,就把它加入:
res.push_back(path);
然后开始回溯:
path.pop_back();
used[i] = false;
例如:
[1,2,3]
↓ 撤销3
[1,2]
↓ 撤销2
[1]
↓ 换一个选择
[1,3]
这样就能不断尝试其他排列。
三个数组分别干什么
nums
原始数字:
[1,2,3]
path
当前正在构造的排列:
[]
[1]
[1,2]
[1,2,3]
used
记录哪些位置已经用过:
nums = [1, 2, 3]
used = [true, false, false]
↑
1 已经使用
res
保存最终所有完整排列:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
这道题最核心的模板
以后遇到类似回溯题,可以先想到:
void backtrack(...) {
// 结束条件
if (...) {
保存结果;
return;
}
for (...) {
if (当前选择不能用)
continue;
// 做选择
...
// 递归
backtrack(...);
// 撤销选择
...
}
}
在这题里就是:
path.push_back(nums[i]);
used[i] = true;
backtracing(nums, used, res, path);
path.pop_back();
used[i] = false;
可以直接记一句:
回溯 = 做选择 → 递归 → 撤销选择。
而这题的关键判断就是:
used防止同一个数字在一个排列中重复使用,path保存当前排列,res保存最终答案。
