题目
给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
输入: [1,2,2]
输出:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
分析
与 子集I 的区别在于 nums 包含了重复的元素。那么只需要先将 nums 进行排序(将重复的值集中到一起),然后再填加额外一行代码去重就可以了。
如上图,nums = [1, 2, 2], 为两个2加标记,用于区分。
for (int i = pos; i < nums.length; i++) {
if(i != pos && nums[i] == nums[i - 1]) continue;
path.add(nums[i]);
subsetsHelper(result, path, nums, i + 1);
path.remove(path.size() - 1);
}
比如:在根节点时,pos = 0,然后逐个循环 nums 中的元素,遇到 时, 加入路径 path,遇到
时,就直接跳过。否则,子集
{ } 和子集{
} 就重复了。
所以最关键的一句话就是:
if(i != pos && nums[i] == nums[i - 1]) continue;
这个技巧在 三数之和 和 全排列II 中都有用到。
代码
class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
if (nums == null || nums.length == 0) return result;
Arrays.sort(nums);
subsetsHelper(result, new ArrayList<>(), nums, 0);
return result;
}
private void subsetsHelper(List<List<Integer>> result, List<Integer> path, int[] nums, int pos) {
result.add(new ArrayList<Integer>(path));
for (int i = pos; i < nums.length; i++) {
if(i != pos && nums[i] == nums[i - 1]) continue;
path.add(nums[i]);
subsetsHelper(result, path, nums, i + 1);
path.remove(path.size() - 1);
}
}
}