Description
Given a list of numbers that may has duplicate numbers, return all possible subsets
Notice
- Each element in a subset must be in non-descending order.
- The ordering between two subsets is free.
- The solution set must not contain duplicate subsets
Example
If S = [1,2,2]
, a solution is:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
Solution
public class Solution {
/*
* @param nums: A set of numbers.
* @return: A list of lists. All valid subsets.
*/
public List<List<Integer>> subsetsWithDup(int[] nums) {
// write your code here
List<List<Integer>> results = new ArrayList<>();
if (nums == null) {
return results;
}
if (nums.length == 0) {
results.add(new ArrayList<Integer>());
}
Arrays.sort(nums); //排序,将重复元素都放在一起
dfsHelper(0, nums, new ArrayList<Integer>(), results);
return results;
}
//如何去除重复:排序,且按顺序取数,不能间隔取数。如{1, 2(1), 2(2)},规定{1, 2(1)}和{1, 2(2)}重复,不能跳过2(1)取2(2)。程序语言就是,当前数字与前一个数字相同时,前一个数字需要在当前的subset中,不能跳过前一个数字只取当前的数字。
private void dfsHelper(int startIndex,
int[]nums,
ArrayList<Integer> subset,
List<List<Integer>> results) {
//deep copy subset & add to results
results.add(new ArrayList<Integer>(subset));
for (int i = startIndex; i < nums.length; i++) {
//判断首先保证i不为0,防止数组越界。前一个数与当前的数相等。前一个数为startIndex - 1当前的数为i且i >= startIndex + 1时,中间至少隔一个数字,此时的情况才出现跳跃取数。
// if (i != 0 && nums[i] == nums[i - 1] && i > startIndex) {
if (i != startIndex && nums[i] == nums[i - 1]) {//若i != startIndexs时则i > startIndex,且i一定不为0,因为startIndex最小是0,因此不用单独判断i != 0的情况。
continue;
}
subset.add(nums[i]);
dfsHelper(i + 1, nums, subset, results);
subset.remove(subset.size() - 1);
}
}
}
总结
如何避免重复:
- 排序(将重复的元素都放到一起,方便后面判断)
- 按顺序取数,不能间隔取数。如{1, 2(1), 2(2)},规定{1, 2(1)}和{1, 2(2)}重复,不能跳过2(1)取2(2)。程序语言就是,当前数字与前一个数字相同时,前一个数字需要在当前的subset中,不能跳过前一个数字只取当前的数字。也就是说,如果有重复的数字,只能按顺序取出,不能有间隔,有了顺序就不会出现重复的情况发生了。