• 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 }
    View Code

    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 }
    View Code

     性能测试:

    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

  • 相关阅读:
    ALINK(十):数据导入与导出 (三)Catalog读入 (CatalogSourceBatchOp)
    ALINK(九):数据导入与导出 (二)Text文件读入 (TextSourceBatchOp)
    ALINK(八):数据导入与导出 (一)CSV文件读入 (CsvSourceBatchOp)
    机器学习sklearn(四): 数据处理(一)数据集拆分(一)train_test_split
    机器学习sklearn(三):加载数据集(数据导入)
    机器学习sklearn(二):SKLEARN快速开始
    机器学习sklearn(一):教程与资料
    程序员的代码的基本素养
    mysql常用函数和语句模式
    BootStrap学习
  • 原文地址:https://www.cnblogs.com/yuzhangcmu/p/4211815.html
Copyright © 2020-2023  润新知