Given a collection of integers that might contain duplicates, S, return all possible subsets.
Note:
For example,
If S = [1,2,2]
, a solution is:
[ [2], [1], [1,2,2], [2,2], [1,2], [] ]
跟subsets这道题非常相像,除了S中会有重复的元素,那么会有什么影响呢?看一个例子:
S = [1,1]
根据subsets中的算法,生成的子集如下:
[ [], [1], [1], [1,1] ]
显然[1],[1]这两个是重复的,需要去掉。那么我们怎么判重?只需要在递归函数的循环里面加上如下判断
if(i != pos && s[i] == s[i - 1]) continue; 就可以了。
理解这个判断的关键,是搞清楚递归函数
public void subsetsDfs(int[] s,int level,int pos,ArrayList<Integer> result,List<List<Integer>> answer)
中pos变量的含义。
在这个函数中,level表示要生成的子集的长度,pos则表示目前要生成子集的第pos位上的元素。那么当i==pos的时候,说明子集中第pos位上的元素还没有生成过,那么即使s[i]==s[i-1],它们在生成的子集中所占有的位置不同(例如例子中的[1,1]中的两个1分别在生成的子集的第0位和第1位上),s[i]就可以加到这个子集上去。但是当i != pos的时候,说明生成的子集上第pos位已经有元素了,如果当前的s[i]和这个元素s[i-1]相等,那么就没有必要再在这个位置上重复放置s[i]了(例如上述例子中已经有子集[1]的时候,不能够再生成子集[s[1]=1]了)。
最后实现的代码如下:
1 public class Solution { 2 public void subsetsDfs(int[] s,int level,int pos,ArrayList<Integer> result,List<List<Integer>> answer){ 3 if(result.size() == level){ 4 answer.add(new ArrayList<Integer>(result)); 5 return; 6 } 7 for(int i = pos;i < s.length;i++){ 8 if(i != pos && s[i] == s[i - 1]) 9 continue; 10 result.add(s[i]); 11 subsetsDfs(s, level, i+1, result, answer); 12 result.remove(result.size()-1); 13 } 14 } 15 public List<List<Integer>> subsetsWithDup(int[] S) { 16 Arrays.sort(S); 17 List<List<Integer>> answer = new ArrayList<List<Integer>>(); 18 ArrayList<Integer> result = new ArrayList<Integer>(); 19 20 for(int i = 0;i <= S.length;i++) 21 subsetsDfs(S, i, 0, result, answer); 22 return answer; 23 } 24 }