Subsets, Subsets II
- Subsets
- 问题描述:给定一个不重复的数组A,让计算A中所有数字的排列组合
- 解决思路:利用DFS来计算所有的组合。
- 例如A中的数字是1~3
- 首先我们可以选择{}->{1} -> {1, 2} - >{1, 2, 3} - >{1, 3} - >{2} - > {2, 3} -> {3}
- 对于第i个数字,我们可以选择将其加入集合中,构成一个新的subset加入res中,然后再递归的处理i+1.
- 代码:
void subsetsBase(vector<int>& nums, vector<vector<int>>& res, int s, vector<int>& cur){
int last_index = -1;
for(int i=s;i<nums.size();i++){
if(last_index != -1 && nums[i] == nums[last_index])
continue;
cur.push_back(nums[i]);
res.push_back(cur);
subsetsBase(nums, res, i + 1, cur);
cur.pop_back();
last_index = i;
}
}
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> res;
res.push_back({});
subsetsBase(nums, res, 0, {});
return res;
}
- Subsets II
- 问题描述:给定一个有重复的数组A,让计算A中所有数字的排列组合。
- 解决思路:
- 基于Subsets I
- 我们先对A进行排序,使得A是个有序的数组。
- 针对某一次递归来讲,我们计算i~j的有序数组,如果A[i+1] = A[i],则我们可以跳过i+1, 直到A[z] != A[i],才开始。这样就避免了重复。
- 代码:
void subsetsBase(vector<int>& nums, vector<vector<int>>& res, int s, vector<int>& cur){
int last_index = -1;
for(int i=s;i<nums.size();i++){
if(last_index != -1 && nums[i] == nums[last_index])
continue;
cur.push_back(nums[i]);
res.push_back(cur);
subsetsBase(nums, res, i + 1, cur);
cur.pop_back();
last_index = i;
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(), nums.end());
res.push_back({});
vector<int> tmp = {};
subsetsBase(nums, res, 0, tmp);
return res;
}
- 非递归方案
- 我们首先考虑有多少个子集。
- 针对重复的情况来说,每个元素都可以选择放或者不放,所以一共是2^N个。现在我们给每个子集都生成一个下标
[
1
,
2
n
]
[1, 2^n]
[1,2n].我们换个角度来看:
- 一开始没有元素对应自己的下标是:1-2^0 {}
- 第一个元素:
2
0
+
1
t
o
2
1
2^0+1\ to\ 2^1
20+1 to 21 {1}
- 第二个元素:
2
1
+
1
t
o
2
2
2^1+1\ to\ 2^2
21+1 to 22 {2}, {1, 2}
- 第三个元素:
2
2
+
1
t
o
2
3
2^2+1\ to\ 2^3
22+1 to 23 {3}, {1, 3}, {2, 3}, {1, 2, 3}
- 所以针对每个元素,他所形成的子集个数增益就是前N个元素形成的子集个数的总和。因为前面的每个自己加上这个元素都会形成一个新的子集。
- 针对有重复的话: 每个元素都可以选择放或者不放,放的话可以选择放1~k个,k是该元素的总个数。
- 所以针对每个元素,他所形成的子集个数增益就是前N个元素形成的子集个数的总和乘以该元素的个数。
- 所以元素总个数是(k1+1) * (k2 + 1) * (k3 + 1) … * (kn + 1)
- 思路:
- 我们首先对A进行排序,主要是让相同的是相邻的元素。
- 初始化我们的res = [{}]
- 针对A中的每个元素x, 重复了k次
- 新形成的元素就是针对res中的每个子集,将元素x添加1–k次。
- 代码:
vector<vector<int>> subsetsWithDupV2(vector<int>& nums){
vector<vector<int>> res;
sort(nums.begin(), nums.end());
res.push_back({});
int i=0;
while(i<nums.size()){
int count = 0;
while((i+count) < nums.size() && nums[i+count] == nums[i]){
count += 1;
}
int k = (int) res.size();
for(int j=0;j<k;j++){
vector<int > instance = res[j];
for(int z=0;z<count;z++){
instance.push_back(nums[i]);
res.push_back(instance);
}
}
i += count;
}
return res;
}