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
题解:
- 回溯法
class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
Arrays.sort(nums);
Set<List<Integer>> ans = new HashSet<>();
List<Integer> cur = new ArrayList<>();
dfs(nums, 0, cur, ans);
return new ArrayList<>(ans);
}
/**
* @param nums 原输入数组
* @param u 当前决策到原输入数组中的哪一位
* @param cur 当前方案
* @param ans 最终结果集
*/
void dfs(int[] nums, int u, List<Integer> cur, Set<List<Integer>> ans) {
// 所有位置都决策完成,将当前方案放入结果集
if (nums.length == u) {
ans.add(new ArrayList<>(cur));
return;
}
// 选择当前位置的元素,往下决策
cur.add(nums[u]);
dfs(nums, u + 1, cur, ans);
// 不选当前位置的元素(回溯),往下决策
cur.remove(cur.size() - 1);
dfs(nums, u + 1, cur, ans);
}
}
时间复杂度:排序时间\(O(nlogn)\),爆搜复杂度为\(O(2^n)\),每个方案通过深拷贝存入答案,为\(O(n)\),整体时间复杂度为\(O(n\times2^n)\)
空间复杂度:总共有\(2^n\)个方案,每个方案最多占用\(O(n)\)空间,整体为\((n\times2^n)\)
- 状态压缩
class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
Arrays.sort(nums);
int n = nums.length;
Set<List<Integer>> ans = new HashSet<>();
List<Integer> cur = new ArrayList<>();
// 枚举 i 代表,枚举所有的选择方案状态
// 例如 [1,2],我们有 []、[1]、[2]、[1,2] 几种方案,分别对应了 00、10、01、11 几种状态
for (int i = 0; i < (1 << n); i++) {
cur.clear();
// 对当前状态进行诸位检查,如果当前状态为 1 代表被选择,加入当前方案中
for (int j = 0; j < n; j++) {
int t = (i >> j) & 1;
if (t == 1) cur.add(nums[j]);
}
// 将当前方案中加入结果集
ans.add(new ArrayList<>(cur));
}
return new ArrayList<>(ans);
}
}