描述
给定一个可能具有重复数字的列表,返回其所有可能的子集
注意事项
子集中的每个元素都是非降序的
两个子集间的顺序是无关紧要的
解集中不能包含重复子集
样例
如果 S = [1,2,2],一个可能的答案为
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
挑战
你可以同时用递归与非递归的方式解决么?
代码
class Solution {
/**
* @param nums: A set of numbers.
* @return: A list of lists. All valid subsets.
*/
public ArrayList<ArrayList<Integer>> subsetsWithDup(int[] nums) {
ArrayList<ArrayList<Integer>> results = new ArrayList<>();
if (nums == null || nums.length == 0) {
return results;
}
Arrays.sort(nums);
ArrayList<Integer> subset = new ArrayList<Integer>();
subsetWithDupHelper(nums, 0, subset, results);
return results;
}
private void subsetWithDupHelper(int[] nums,
int startIndex,
ArrayList<Integer> subset,
ArrayList<ArrayList<Integer>> results) {
results.add(new ArrayList<Integer>(subset));
for (int i = startIndex; i < nums.length; i++) {
/* 本来初值是令i = startIndex,正常运行代码不应该出现取第二个不取
* 第一个的情况,但此条if本身就是用于表示异常的,所以一切就变得
* 可以理解了
*/
if (i != 0 && nums[i] == nums[i - 1] && i > startIndex){
/* i != 0是为了防止 i - 1越界,
* nums[i] = nums[i - 1] 即当前数等于前一个数,
* 从下面 subset 两行代码可以看出如果 nums[i - 1] 被加入 subset,
* 那么下一个startIndex = i - 1 + 1 = i;
* i > startIndex等价于i >= startIndex + 1,而上一个数是startIndex - 1;
* 说明在startIndex - 1和startIndex + 1间存在一个数,
* 存在当前值nums的前一个与它相等的值并没有被添加到list里,这样会重复
*/
continue;
}
subset.add(nums[i]);
subsetWithDupHelper(nums, i + 1, subset, results);
subset.remove(subset.size() - 1);
}
}
}
本题和subset相比就多了一个去重的过程,去重的逻辑已经在注释里说清楚了,稍微补充点就是比如数组是[1,2,2],第一个2用A表示,第二个2用B表示,我们要的顺序是[1,A],此时的要去的重就是[1,B]这种组合,比较容易混淆的是[1,A,B]这种情况A,B两个2在同一个list里并不算重复,去除的是两个list之间的重复情况