给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
输入: [1,2,2]
输出:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
有两种重复原因:
1、不同位置的元素组成的集合是同一个子集,顺序相同:
例如:[2,1,2,2]
选择第1,2,3个元素组成的子集:[2,1,2];
选择第1,2,4个元素组成的子集: [2,1,2];
2、不同位置的元素组成的集合是同一子集,虽然顺序不同,但仍然代表了同一子集,因为集合中的元素是无序的。
例如:[2,1,2,2]
选择第1,2,3个元素组成的子集:[2,1,2];
选择第2,3,4个元素组成的子集:[1,2,2];
不同位置的元素组成的集合是同一个子集,子集的各个元素顺序相同,或顺序不同,解决方法
例如:[2,1,2,2]
选择第1,2,3个元素组成的子集:[2,1,2];
选择第1,2,4个元素组成的子集: [2,1,2];
选择第2,3,4个元素组成的子集:[1,2,2];
解决方案
先对原始nums数组进行排序,再使用set去重
例如:[2,1,2,2]排序后:[1,2,2,2],无论如何选择,均出现[1,2,2]
代码如下:
//类似子集I那道题
class Solution {
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
vector<vector<int>> result;
vector<int> item;
set<vector<int>> res_set; //去重使用的集合
sort(nums.begin(),nums.end()); //对nums数组进行排序
result.push_back(item);
generate(0, nums, result, item, res_set);
return result;
}
private:
void generate(int i, vector<int>& nums, vector<vector<int>> &result, vector<int>& item, set<vector<int>>& res_set){
if(i >= nums.size()){
return;
}
item.push_back(nums[i]);
if(res_set.find(item) == res_set.end()){ //如果res_set集合中,无法找到item
result.push_back(item); //将item放入result数组中
res_set.insert(item); //将item放入去重集合res_set中
}
generate(i+1, nums, result, item, res_set);
item.pop_back();
generate(i+1, nums, result, item, res_set);
}
};
测试程序如下:
int main()
{
vector<int> nums;
nums.push_back(2);
nums.push_back(1);
nums.push_back(2);
nums.push_back(2);
vector<vector<int>> result; //最终数组
Solution solve;
result = solve.subsetsWithDup(nums);
for (int i = 0; i < result.size(); i++){
if (result[i].size() == 0) {
printf("[]");
}
for (int j = 0; j < result[i].size(); j++) {
printf("[%d]", result[i][j]);
}
printf("\n");
}
return 0;
}
结果如下: