之前的全排列系列是有細節區別的,一直不理解。
- 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