90 子集 II
给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的 子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
示例 1:
输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]
示例 2:
输入:nums = [0]
输出:[[],[0]]
提示:
1 <= nums.length <= 10
-10 <= nums[i] <= 10
法1

对于本题,可以对其使用类似 【47 全排列 II】 的方法,在准备选中 nums[i]==nums[i-1]的第i元素时,保证其在原数组vis[i-1]元素也访问过,保证是在原数组中从左到右依次选中的就可以只保留多种顺序的第一种顺序
class Solution {
public:
vector<vector<int>> subsetsWithDup(vector<int> &nums) {
sort(nums.begin(), nums.end());
int n = nums.size();
vector<vector<int>> ans; // 存储最终结果
vector<int> path; // 当前子集
vector<bool> on_path(n, false);
vector<bool> vis(n, false);
function<void(int)> dfs = [&](int i) {
if (i == n) {
ans.push_back(path); // 将当前子集加入结果
return;
}
// 访问分支:包含当前元素
if ((i < 1) || (nums[i] != nums[i - 1]) || (nums[i] == nums[i - 1] && on_path[i - 1])) {
path.push_back(nums[i]);
on_path[i] = true;
dfs(i + 1);
// 恢复现场:不包含当前元素
path.pop_back();
on_path[i] = false;
}
// 不访问分支:不包含当前元素
dfs(i + 1);
};
dfs(0);
return ans;
}
};
法2

在寻找一组重复字符数组的不同集合时,我们可以将结果集合映射到满1的路径上,只对这条路径递归即可找出不同集合
- 选
- 递归
- 不选
- 结束
class Solution {
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
ranges::sort(nums);
int n = nums.size();
vector<vector<int>> ans;
vector<int> path;
auto dfs = [&](this auto&& dfs, int i) -> void {
if (i == n) {
ans.push_back(path);
return;
}
// 选 x
int x = nums[i];
path.push_back(x);
dfs(i + 1);
path.pop_back(); // 恢复现场
// 不选 x,那么后面所有等于 x 的数都不选
// 如果不跳过这些数,会导致「选 x 不选 x'」和「不选 x 选 x'」这两种情况都会加到 ans 中,这就重复了
i++;
while (i < n && nums[i] == x) {
i++;
}
dfs(i);
};
dfs(0);
return ans;
}
};
作者:灵茶山艾府
链接:https://leetcode.cn/problems/subsets-ii/solutions/3036436/liang-chong-fang-fa-xuan-huo-bu-xuan-mei-v0js/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

浙公网安备 33010602011771号