之前的全排列系列是有细节区别的,一直不理解。
- 1.
dfs(nums,res,out, i + 1);
强调的是下一个状态选或不选 - 2.
dfs(nums,res,out, start + 1);
强调的是下一个子集解
全排列系列
77. 组合
输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
class Solution {
public:
void help(vector<vector<int>>&res, vector<int>&out, int n, int k, int level)
{
if (out.size() == k) { res.push_back(out); return; }
for (int i = level; i <= n; i++)
{
out.push_back(i);
help(res, out, n, k, i + 1);
out.pop_back();
}
}
vector<vector<int>> combine(int n, int k) {
vector<vector<int>>res;
vector<int>out;
help(res,out,n,k,1);
return res;
}
};
78.子集
例如:nums=[1,2,3]
res:[[],[1],[1,2],[1,2,3],[1,3],[2],[2,3],[3]]
分析:由于原集合每一个数字只有两种状态,要么存在,要么不存在,那么在构造子集时就有选择和不选择两种情况,所以可以构造一棵二叉树,左子树表示选择该层处理的节点,右子树表示不选择,最终的叶节点就是所有子集合,树的结构如下:
[]
/ \
/ \
/ \
[1] []
/ \ / \
/ \ / \
[1 2] [1] [2] []
/ \ / \ / \ / \
[1 2 3] [1 2] [1 3] [1] [2 3] [2] [3] []
class Solution {
public:
//回溯法,一系列全排列
void dfs(vector<int>& nums,vector<vector<int>>&res, vector<int>&out, int start)
{
res.push_back(out);//每个状态都压进去
for (int i = start; i < nums.size(); i++)
{
out.push_back(nums[i]);
dfs(nums,res,out, i + 1);
out.pop_back();
}
}
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>>res;
vector<int>out;
dfs(nums,res,out,0);
return res;
}
};
static const auto speedup=[](){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
return nullptr;
}();
假设nums[1,2,3]如果是写成dfs(nums,res,out, start + 1);
结果是
[[], [1], [1, 2], [1, 2, 3], [1, 3], [1, 3, 3], [2], [2, 2], [2, 2, 3], [2, 3], [2, 3, 3], [3], [3, 2], [3, 2, 3], [3, 3], [3, 3, 3]]
出现[2,2]原因是i已经到了1,但是还要递归start+1即1.
90. 子集 II
利用上面的代码nums=[1,2,2],
其结果是[[],[1],[1,2],[1,2,2],[1,2],[2],[2,2],[2]]
那么我需要剪枝:
[]
/ \
/ \
/ \
[1] []
/ \ / \
/ \ / \
[1 2] [1] [2] []
/ \ / \ / \ / \
[1 2 2] [1 2] X [1] [2 2] [2] X []
代码只需在原有的基础上增加一句话,while (S[i] == S[i + 1]) ++i; 这句话的作用是跳过树中为X的叶节点,因为它们是重复的子集,应被抛弃。代码如下:
class Solution {
public:
void dfs(vector<int>& nums,vector<vector<int>>&res, vector<int>&out, int start)
{
res.push_back(out);
for (int i = start; i < nums.size(); i++)
{
out.push_back(nums[i]);
dfs(nums,res,out, i + 1);
out.pop_back();
//while(i!=0&&nums[i]==nums[i-1])i++;//已经添加了
while((i!=nums.size()-1)&&nums[i]==nums[i+1])i++;
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
vector<vector<int>>res;
vector<int>out;
sort(nums.begin(),nums.end());
dfs(nums,res,out,0);
return res;
}
};
写成这样更快:
不要后加入res,先加
class Solution {
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
vector<vector<int>> res ;
int len = nums.size();
sort(nums.begin(),nums.end());
vector<int> temp;
res.push_back(temp);
fun(nums,0,temp,res);
return res;
}
void fun(vector<int>& nums,int i,vector<int>& temp,vector<vector<int>> &res){
for(int j = i;j<nums.size();j++){
if(j>i&&nums[j]==nums[j-1])
continue;
temp.push_back(nums[j]);
res.push_back(temp);
fun(nums,j+1,temp,res);
temp.pop_back();
}
return;
}
};
[1]https://blog.csdn.net/u010500263/article/details/18435495
[2]https://www.cnblogs.com/grandyang/p/4332522.html