文章目录
- 46. 全排列
- 47. 全排列 II
- 78. 子集
46. 全排列
class Solution {
public:
vector<vector<int>> ans;
void fun(vector<int>& nums, int startIdx, int n) {
if (startIdx == n) {
ans.emplace_back(nums);
return;
}
for(int i = startIdx; i < n; i++){
swap(nums[startIdx], nums[i]);
fun(nums, startIdx + 1, n); // 表示已经放好了startIdx位置,现在需要放好startIdx + 1的位置
swap(nums[startIdx], nums[i]);
}
}
vector<vector<int>> permute(vector<int>& nums) {
fun(nums, 0, nums.size());
return ans;
}
};
47. 全排列 II
对于全排列去重问题,我们在每个节点都要遍历所有的元素,如果使用过了,就跳过,没使用过就要去重
class Solution {
public:
vector<vector<int>> ans;
vector<int> path;
vector<bool> used;
vector<int> nums;
int n;
void dfs(int level){
if(level == n){
ans.push_back(path);
return;
}
for(int i = 0; i < n; i++){
// 同一树层去重:对于同一层,相同的元素之间若前面的元素没使用,后面的元素也不要使用
if(used[i] || (i > 0 && !used[i - 1] && nums[i] == nums[i - 1])) continue;
used[i] = true;
path.push_back(nums[i]);
dfs(level + 1);
path.pop_back();
used[i] = false;
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(), nums.end());
this->nums = nums;
n = nums.size();
used.resize(n, false);
dfs(0);
return ans;
}
};
78. 子集
求子集时,每个节点都要收集path
下一层横向增长的时,需要往i之后增长,而不是往startIdx后增长
for循环从startIdx开始,控制横向增长
递归调用,用i + 1控制纵向增长
如果纵向增长时,传入fun(startIdx + 1),会导致每层增长的结果都一样
class Solution {
public:
vector<vector<int>> ans;
vector<int> path;
void fun(int startIndex, const vector<int>& nums){
ans.push_back(path);
for(int i = startIndex; i < nums.size(); i++){
path.push_back(nums[i]);
fun(i + 1, nums); // 下一层横向增长的时,需要往i之后增长,而不是往startIdx后增长
path.pop_back();
}
}
vector<vector<int>> subsets(vector<int>& nums) {
fun(0, nums);
return ans;
}
};