46. 全排列
给定一个不含重复数字的数组 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
-10 <= nums[i] <= 10
nums
中的所有整数 互不相同
思路: 对于组合、排列类问题,可以使用回溯算法解决。首先定义 result,容器的容器,用来存储最终的全部排列;定义 current,一个整型容器,存储当前的一种排列;定义 bool 型容器,记录原始数组 nums 中哪些元素在当前排列 current 中已经使用过,初始化为全部 false;然后定义回溯函数,回溯函数在执行过程中会多次纵向递归调用(递归深度为 nums.size()+1
),每调用一层,current 中就多一个 nums 中未使用过的元素,直到 current 的大小和 nums 相同,最底层的回溯函数就执行完毕,成功 return,退回到上一层的回溯函数,执行回退操作,将 current 当前的最后一个元素标记为未使用并删除,此时当前层的 for 循环也执行完毕,当前层回溯函数执行完毕,退回到再上一层回溯函数,继续将 current 当前的最后一个元素标记为未使用并删除,此时 for 循环还差最后一次循环才能结束,执行最后一次循环,遍历到 nums 的最后一个元素,该元素在上一层回溯函数中已经被标记为未使用,因此可以加入到 current 中,此时 current 未满,继续进入下一层回溯函数,添加 nums 中未被使用过的元素,然后 current 满,回溯函数退出,继续执行回退操作,将 current 当前的最后一个元素标记为未使用并删除,此时当前层的 for 循环也执行完毕,当前层回溯函数执行完毕,退回到再上一层回溯函数,依此类推,直到 result 保存所有可能排列。
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int>> result; // 存储最终结果
vector<int> current; // 存储当前正在构建的组合
vector<bool> used(nums.size(), false); // 记录哪些数字用过
// 定义回溯函数
function<void()> backtrack = [&]() { // 通过[&]以引用形式捕获所有外部变量,而无需显式的传入参数
// 如果当前组合的长度等于nums.size(),将其加入结果
if (current.size() == nums.size()) {
result.push_back(current);
return;
}
// 遍历nums中所有元素
for (int i = 0; i < nums.size(); i++) {
if (!used[i]) { // 如果当前元素还没有使用过
current.push_back(nums[i]); // 将当前数字加入组合
used[i] = true; // 标记该数字已用过
backtrack(); // 递归调用,继续构建组合
used[i] = false; // 回溯,恢复该数字未用过
current.pop_back(); // 回溯,移除最后一个数字
}
}
};
backtrack(); // 开始调用回溯函数
return result; // 返回最终结果
}
};