
首先排列是有序的,也就是说 [1,2] 和 [2,1] 是两个集合,这和之前分析的子集以及组合所不同的地方。
可以看出元素1在[1,2]中已经使用过了,但是在[2,1]中还要在使用一次1,所以处理排列问题就不用使用startIndex了。
但排列问题需要一个used数组,标记已经选择的元素,如图橘黄色部分所示:

可以看出叶子节点,就是收割结果的地方。
那么什么时候,算是到达叶子节点呢?
当收集元素的数组path的大小达到和nums数组一样大的时候,说明找到了一个全排列,也表示到达了叶子节点。
cpp
if (path.size() == nums.size()) {
result.push_back(path);
return;
}
本题的for循环里不用startIndex了。
因为排列问题,每次都要从头开始搜索,例如元素1在[1,2]中已经使用过了,但是在[2,1]中还要再使用一次1。
而used数组,其实就是记录此时path里都有哪些元素使用了,一个排列里一个元素只能使用一次。
cpp
class Solution {
public:
vector<vector<int>> result; // 存储所有排列结果的二维数组
vector<int> path; // 存储当前正在构建的排列(路径)
// 回溯函数
// nums: 原始输入数组
// used: 标记数组元素是否已被使用的布尔数组
void backtracking (vector<int>& nums, vector<bool>& used) {
// 终止条件:当前路径长度等于原始数组长度
// 说明已经构造出一个完整的排列
if (path.size() == nums.size()) {
result.push_back(path); // 将当前排列加入结果集
return; // 返回上一层递归
}
// 遍历所有可能的元素选择
for (int i = 0; i < nums.size(); i++) {
// 跳过已使用的元素(避免重复选择)
if (used[i] == true) continue;
// 做出选择
used[i] = true; // 标记当前元素为已使用
path.push_back(nums[i]); // 将当前元素加入路径
// 递归进入下一层决策树
backtracking(nums, used);
// 撤销选择(回溯)
path.pop_back(); // 从路径中移除最后一个元素
used[i] = false; // 标记当前元素为未使用
}
}
// 主函数:生成全排列
vector<vector<int>> permute(vector<int>& nums) {
result.clear(); // 清空结果集(防止多次调用时数据残留)
path.clear(); // 清空当前路径
vector<bool> used(nums.size(), false); // 初始化used数组,所有元素初始未使用
backtracking(nums, used); // 开始回溯
return result; // 返回所有排列结果
}
};
以 nums = [1,2,3] 为例,详细分析代码执行过程
初始状态
nums = [1,2,3] used = [false, false, false] path = [] result = []
递归 backtracking ([1,2,3],[false, false, false])
if判断,path = [] (长度0 < 3,继续执行
cppfor (int i = 0; i < nums.size(); i++) { if (used[i] == true) continue; // path里已经收录的元素,直接跳过 used[i] = true; path.push_back(nums[i]); backtracking(nums, used); path.pop_back(); used[i] = false; }
开始for循环,i=0 if (used[i] == true) → 因为used[0]=false,所以不执行if语句 used[0]=true,used=[True,F,F] path.push_back(nums[0]) → path.push_back(1),path变为[1] 调用backtracking(nums, used)
递归 backtracking ([1,2,3],[true, false, false])
path=[1], used=[T,F,F] if (path.size() == nums.size()) → 1 == 3 ❌,所以不执行if语句 for 开始循环 , i=0: if (used[i] == true) → used[0]==true ✅,执行continue,跳到下一个i i++,现在i=1: if (used[i] == true) → used[1]==false ❌,所以不执行if语句 used[1]=true,used变为[T,T,F] path.push_back(nums[0]) → path.push_back(2),path变为[1,2] backtracking(nums, used)
递归 backtracking ([1,2,3],[true, true, false])
path=[1,2], used=[T,T,F] if (path.size() == nums.size()) → 2 == 3 ❌,不执行if语句 for开始循环 , i=0: if (used[i] == true) → used[0]==true ✅,continue i++,i=1: 第13行: if (used[i] == true) → used[1]==true ✅,continue 循环 i=2: if (used[i] == true) → used[2]==false ❌,不执行if语句 used[i] = true → used[2]=true,used变为[T,T,T] path.push_back(nums[2]) → path.push_back(3),path变为[1,2,3] backtracking(nums, used)
递归 backtracking ([1,2,3],[true, true, true])
path=[1,2,3], used=[T,T,T] if (path.size() == nums.size()) → 3 == 3 ✅,进入if 执行if语句,result.push_back(path) → result为[1,2,3] return → 这个递归结束,返回到上一个递归
返回backtracking ([1,2,3],[true, true, false])
之前path=[1,2,3], used=[T,T,T] 执行回溯 path.pop_back() → path变为[1,2] used[i] = false → used[2]=false,used变为[T,T,F] i++,i=3 ,for循环结束 (i从2增加到3,循环条件i<3不满足) 这个递归结束
.........
.........
.........