Subsets II
Given an integer array nums that may contain duplicates, return all possible subsets(the power set). The solution set must not contain duplicate subsets. Return the solution in an order.
题目的输入是一个数组,其中可能含有重复的元素;要求的结果是这个数组的所有子集的集合,也就是幂集,且结果集合中不能含有重复的集合,但是不要求顺序。
而且我注意到题目的约束条件,数组长度居然最多只有10,数组元素的绝对值最大值也只有10
既然这样,那么使用暴力破解方法可能会成功
-
解法一
首先对输入数组进行排序,然后使用回溯法得出数组元素所有可能的组合,再利用Set集合对得到的结果进行去重处理,即可得到结果。
代码如下:
public class Solution { public List<List<Integer>> subsetsWithDup(int[] nums) { Arrays.sort(nums); Set<List<Integer>> result = new HashSet<>(); List<Integer> cur = new ArrayList<>(); flash(nums, 0, cur, result); return new ArrayList<>(result); } /* * @param nums 原输入数组 * @param now 当前决策到数组中的哪一位置 * @param current 当前方案 * @param result 最终方案 */ public void flash(int[] nums, int now, List<Integer> current, Set<List<Integer>> result) { //所有位置都决策完毕,将当前方案放入最终结果集 if(nums.length == now) { result.add(new ArrayList<>(current)); return; } //选择当前位置的元素,往下决策 current.add(nums[now]); flash(nums, now+1, current, result); //不选当前位置的元素(回溯),往下决策 current.remove(current.size()-1); flash(nums, now+1, current, result); } }
结果确实可以通过
-
解法二
由于数组的长度只有10,我们可以用一个二进制数的后十位分别表示数组的10个元素有没有被选择。这样就避免了回溯。
同样,最终得到的结果集也需要利用Set进行去重处理。
具体实现的代码如下:
public class Solution2 { public List<List<Integer>> subsetsWithDup(int[] nums) { Arrays.sort(nums); Set<List<Integer>> result = new HashSet<List<Integer>>(); List<Integer> current = new ArrayList<>(); //枚举所有的选择状态,例如[1, 2],它的所有状态就有[],[1],[2],[1,2],分别对应00、01、10、11这几种状态 //可能的状态就有2^n种,这里用移位运算代替求幂,提高效率 int n = nums.length; for(int i = 0; i < (1<<n); i++) { current.clear(); //对当前状态进行逐位检查,如果当前状态为1代表被选择,加入当前方案中 for(int j = 0; j < n; j++) { int temp = (i >> j) & 1; if(temp == 1) current.add(nums[j]); } result.add(new ArrayList<>(current)); } return new ArrayList<>(result); } }
提交结果如下: