力扣 leetcode 90. 子集 II
问题描述
给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
提示:
- 1 <= nums.length <= 10
- -10 <= nums[i] <= 10
示例
示例 1:
输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]
示例 2:
输入:nums = [0]
输出:[[],[0]]
解题思路
本题与力扣 leetcode 78. 子集有异曲同工之妙,但是本题多了一个限制,nums 中的元素现在已经可以重复了,这为我们去除结果中的重复元素带来了更大的挑战。
这里的一个思路是,可以用集合保存已有的结果,或者直接对现有的结果进行遍历,判断是否重复。但是,考虑到 nums[i] == nums[j],则 [nums[i], nums[j]] 和 [nums[j], nums[k]] 有时很难分辨出来。为此,我们可以对结果排序,或者对 nums 排序,保证结果是有序的,这样就方便判断结果是否重复。
因为现在结果已经有序,那我们只需判断结果中相同长度的子数组是否与现有结果相同,如果相同,则放弃此结果。
class Solution {
public:
void pushItem(vector<int>& nums, vector<vector<int>>& res, vector<int>& r, int step, const int maxStep, int idx, int n){
if(step){
step--;
for(int i = idx; i < nums.size() - step; i++){
bool flag = true;
for(int j = res.size() - 1; j >= 0 && res[j].size() == maxStep; j--){
if(nums[i] == res[j][n]){ // 判断结果中是否重复
flag = false;
for(int k = 0; k < n; k++){
if(r[k] != res[j][k]){
flag = true;
break;
}
}
break;
}
}
if(flag){
r[n] = nums[i];
pushItem(nums, res, r, step, maxStep, i + 1, n + 1);
}
}
}
else{
vector<int> tmp(r);
res.push_back(tmp);
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(), nums.end());
const int n = nums.size();
vector<vector<int>> res(1, vector<int> {});
int idx = 0;
for(int i = 1; i <= n; i++){
vector<int> r(i);
pushItem(nums, res, r, i, i, idx, idx);
}
return res;
}
};
本文来自博客园,作者:greatestchen},转载请注明原文链接:https://www.cnblogs.com/greatestchen/p/16964860.html