LeetCode: Subsets & Subsets II
Given a set of distinct integers, S, return all possible subsets.
我想到的算法是这个样子的。我想用的是递归。n个数的subset可以由n-1个数的subset产生。
就是把subset(n-1)以及其中每一个组合加上S[n]。比如[1,2,3] = [], [1], [2], [1,2], []+3, [1]+3, [2]+3, [1, 2]+3;
1 public static ArrayList<ArrayList<Integer>> subsets(int[] S, int aa) { 2 if(aa == 0) { 3 return new ArrayList<ArrayList<Integer>>(); 4 } 5 else if(aa == 1) { 6 ArrayList<ArrayList<Integer>> a = new ArrayList<ArrayList<Integer>>(); 7 ArrayList<Integer> t1 = new ArrayList<Integer>(); 8 t1.add(S[0]); 9 a.add(t1); 10 a.add(new ArrayList<Integer>()); 11 return a; 12 } 13 else { 14 ArrayList<ArrayList<Integer>> Q = new ArrayList<ArrayList<Integer>>(); 15 ArrayList<ArrayList<Integer>> R = new ArrayList<ArrayList<Integer>>(); 16 for (ArrayList<Integer> x : subsets(S, aa-1)) { 17 Q.add(x); 18 } 19 20 R.addAll(Q); 21 for (ArrayList<Integer> x : Q) { 22 ArrayList<Integer> y = new ArrayList<Integer>(x); 23 y.add(S[aa-1]); 24 R.add(y); 25 } 26 return R; 27 }
又学习到一种DFS的方法。[1,2,3,4]的subsets的第一个元素可以是1, 2, 3, 4. 如果第一个是1,那么第二个可是是2,3,4. 第三个可以是第二个元素之后的数。
所以就是先是1,然后是1,2,然后1,2,3,然后1,2,3,4,然后4后面没得选了;回溯到3,上一次3后面选的是4,但是没有其他可以选的了,回溯到2. 2上一次选的是3,这一次课一选4.。。。。。。。
1 public static ArrayList<ArrayList<Integer>> subsets2(int[] S) { 2 ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>(); 3 ArrayList<Integer> tmp = new ArrayList<Integer>(); 4 Arrays.sort(S); 5 res.add(tmp); 6 dfs(res,tmp,S,0); 7 return res; 8 } 9 10 public static void dfs(ArrayList<ArrayList<Integer>> res, ArrayList<Integer> tmp, int[] S, int pos){ 11 for(int i=pos; i<S.length;i++) { 12 tmp.add(S[i]); 13 res.add(new ArrayList<Integer>(tmp)); 14 dfs(res,tmp,S,i+1); 15 tmp.remove(tmp.size()-1); 16 } 17 }
Given a collection of integers that might contain duplicates, S, return all possible subsets.
这一次包含重复元素。按照上面第一种方法,就得到一个组合之后看看result里有没有,如果没有就包含进去。
1 public static ArrayList<ArrayList<Integer>> subsetsWithDup(int[] num) { 2 Arrays.sort(num); 3 return subsets(num, num.length); 4 } 5 public static ArrayList<ArrayList<Integer>> subsets(int[] S, int aa) { 6 if(aa == 0) { 7 return new ArrayList<ArrayList<Integer>>(); 8 } 9 else if(aa == 1) { 10 ArrayList<ArrayList<Integer>> a = new ArrayList<ArrayList<Integer>>(); 11 ArrayList<Integer> t1 = new ArrayList<Integer>(); 12 t1.add(S[0]); 13 a.add(t1); 14 a.add(new ArrayList<Integer>()); 15 return a; 16 } 17 else { 18 ArrayList<ArrayList<Integer>> Q = new ArrayList<ArrayList<Integer>>(); 19 ArrayList<ArrayList<Integer>> R = new ArrayList<ArrayList<Integer>>(); 20 for (ArrayList<Integer> x : subsets(S, aa-1)) { 21 Q.add(x); 22 } 23 24 R.addAll(Q); 25 for (ArrayList<Integer> x : Q) { 26 ArrayList<Integer> y = new ArrayList<Integer>(x); 27 y.add(S[aa-1]); 28 if (!R.contains(y)) 29 R.add(y); 30 } 31 return R; 32 }
用dfs的话,就在回溯的时候判断上一次使用的下一个元素和当前的时候一样,如果一样的话就跳过。这种方法因为不用经常在ArrayList里查找,因此速度会快一点。
1 public static ArrayList<ArrayList<Integer>> subsets2(int[] S) { 2 ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>(); 3 ArrayList<Integer> tmp = new ArrayList<Integer>(); 4 Arrays.sort(S); 5 res.add(tmp); 6 dfs(res,tmp,S,0); 7 return res; 8 } 9 10 public static void dfs(ArrayList<ArrayList<Integer>> res, ArrayList<Integer> tmp, int[] S, int pos){ 11 for(int i=pos; i<S.length;i++) { 12 tmp.add(S[i]); 13 res.add(new ArrayList<Integer>(tmp)); 14 dfs(res,tmp,S,i+1); 15 tmp.remove(tmp.size()-1); 16 while (i<S.length-1 && S[i+1] == S[i]) i++; 17 } 18 }