LeetCode: Subsets 解题报告
Subsets
Given a set of distinct integers, S, return all possible subsets.
Note:
- Elements in a subset must be in non-descending order.
- The solution set must not contain duplicate subsets.
For example,
If S = [1,2,3], a solution is:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
SOLUTION 1:
使用九章算法的模板:
递归解决。
1. 先对数组进行排序。
2. 在set中依次取一个数字出来即可,因为我们保持升序,所以不需要取当前Index之前的数字。
TIME: 227 ms
1 public class Solution { 2 public List<List<Integer>> subsets(int[] S) { 3 List<List<Integer>> ret = new ArrayList<List<Integer>>(); 4 if (S == null) { 5 return ret; 6 } 7 8 Arrays.sort(S); 9 10 dfs(S, 0, new ArrayList<Integer> (), ret); 11 12 return ret; 13 } 14 15 public void dfs(int[] S, int index, List<Integer> path, List<List<Integer>> ret) { 16 ret.add(new ArrayList<Integer>(path)); 17 18 for (int i = index; i < S.length; i++) { 19 path.add(S[i]); 20 dfs(S, i + 1, path, ret); 21 path.remove(path.size() - 1); 22 } 23 } 24 }
SOLUTION 2:
在Solution 1的基础之上,使用Hashmap来记录中间结果,即是以index开始的所有的组合,希望可以加快运行效率,最后时间:
TIME:253 ms.
实际结果与预期反而不一致。原因可能是每次新组装这些解也需要耗费时间
1 // Solution 3: The memory and recursion. 2 public List<List<Integer>> subsets(int[] S) { 3 // 2135 4 List<List<Integer>> ret = new ArrayList<List<Integer>>(); 5 if (S == null) { 6 return ret; 7 } 8 9 Arrays.sort(S); 10 return dfs3(S, 0, new HashMap<Integer, List<List<Integer>>>()); 11 } 12 13 public List<List<Integer>> dfs3(int[] S, int index, HashMap<Integer, List<List<Integer>>> map) { 14 int len = S.length; 15 16 if (map.containsKey(index)) { 17 return map.get(index); 18 } 19 20 List<List<Integer>> ret = new ArrayList<List<Integer>>(); 21 List<Integer> pathTmp = new ArrayList<Integer>(); 22 ret.add(pathTmp); 23 24 for (int i = index; i < len; i++) { 25 List<List<Integer>> left = dfs3(S, i + 1, map); 26 for (List<Integer> list: left) { 27 pathTmp = new ArrayList<Integer>(); 28 pathTmp.add(S[i]); 29 pathTmp.addAll(list); 30 ret.add(pathTmp); 31 } 32 } 33 34 map.put(index, ret); 35 return ret; 36 }
SOLUTION 3:
相当牛逼的bit解法。基本的想法是,用bit位来表示这一位的number要不要取,第一位有1,0即取和不取2种可能性。所以只要把0到N种可能
都用bit位表示,再把它转化为数字集合,就可以了。
Ref: http://www.fusu.us/2013/07/the-subsets-problem.html
There are many variations of this problem, I will stay on the general problem of finding all subsets of a set. For example if our set is [1, 2, 3] - we would have 8 (2 to the power of 3) subsets: {[], [1], [2], [3], [1, 2], [1, 3], [1, 2, 3], [2, 3]}. So basically our algorithm can't be faster than O(2^n) since we need to go through all possible combinations.
There's a few ways of doing this. I'll mention two ways here - the recursive way, that we've been taught in high schools; and using a bit string.
Using a bit string involves some bit manipulation but the final code can be found easy to understand. The idea is that all the numbers from 0 to 2^n are represented by unique bit strings of n bit width that can be translated into a subset. So for example in the above mentioned array we would have 8 numbers from 0 to 7 inclusive that would have a bit representation that is translated using the bit index as the index of the array.
Nr |
Bits |
Combination |
0 |
000 |
{} |
1 |
001 |
{1} |
2 |
010 |
{2} |
3 |
011 |
{1, 2} |
4 |
100 |
{3} |
5 |
101 |
{1, 3} |
6 |
110 |
{2, 3} |
7 |
111 |
{1, 2, 3} |
1 public class Solution { 2 public List<List<Integer>> subsets(int[] S) { 3 List<List<Integer>> ret = new ArrayList<List<Integer>>(); 4 if (S == null || S.length == 0) { 5 return ret; 6 } 7 8 int len = S.length; 9 Arrays.sort(S); 10 11 // forget to add (long). 12 long numOfSet = (long)Math.pow(2, len); 13 14 for (int i = 0; i < numOfSet; i++) { 15 // bug 3: should use tmp - i. 16 long tmp = i; 17 18 ArrayList<Integer> list = new ArrayList<Integer>(); 19 while (tmp != 0) { 20 // bug 2: use error NumberOfTrailingZeros. 21 int indexOfLast1 = Long.numberOfTrailingZeros(tmp); 22 list.add(S[indexOfLast1]); 23 24 // clear the bit. 25 tmp ^= (1 << indexOfLast1); 26 } 27 28 ret.add(list); 29 } 30 31 return ret; 32 } 33 34 }
性能测试:
1. when SIZE = 19:
Subset with memory record: 14350.0 millisec.
Subset recursion: 2525.0 millisec.
Subset Iterator: 5207.0 millisec.
表明带memeory的性能反而不行。而iterator的性能也不并不如。
2. size再继续加大时,iterator的会出现Heap 溢出的问题,且速度非常非常慢。原因不是太懂。
GITHUB: https://github.com/yuzhangcmu/LeetCode_algorithm/blob/master/dfs/Subsets.java
posted on 2015-01-08 20:05 Yu's Garden 阅读(9932) 评论(1) 编辑 收藏 举报