zoukankan      html  css  js  c++  java
  • Leetcode | Subsets I & II

    Subsets I

    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],
    []
    ]

    Method I

    我的做法是产生只有1个数的subset,然后产生有两个数的subset。这里有这么一层关系:

    n+1个数的subset=前n个数的subset + 前n个数的subset都加上第n个数

    比如 S=[1,2,3],产生的序列如下:

    [] ------------[]

    [1]-----------[] [1]

    [2] [1,2]------------[] [1] [2] [1,2]

    [3] [1,3] [2,3] [1,2,3]------------[] [1] [2] [1,2] [3] [1,3] [2,3] [1,2,3]

    为了保证所有集合是升序的,一开始需要对S进行排序。

     1 class Solution {
     2 public:
     3     vector<vector<int> > subsets(vector<int> &S) {
     4         vector<vector<int> > ret;
     5         vector<int> v;
     6         ret.push_back(v);
     7         sort(S.begin(), S.end());
     8         for(int i = 0; i < S.size(); ++i) {
     9             int n = ret.size();
    10             for (int j = 0; j < n; ++j) {
    11                 vector<int> nv(ret[j]);
    12                 nv.push_back(S[i]);
    13                 ret.push_back(nv);
    14             }
    15         }
    16         
    17         return ret;
    18     }
    19 };

    Method II

    递归。每碰到一个数,要么加进去,要么不加进去。最终产生所有集合。

     1 class Solution {
     2 public:
     3     vector<vector<int> > subsets(vector<int> &S) {
     4         sort(S.begin(), S.end());
     5         vector<int> v;
     6         recursive(S, 0, v);
     7         return ret;
     8     }
     9     
    10     void recursive(vector<int> &S, int i, vector<int> &v) {
    11         if (i == S.size()) {
    12             ret.push_back(v);
    13             return;
    14         }    
    15         recursive(S, i + 1, v);
    16         
    17         v.push_back(S[i]);
    18         recursive(S, i + 1, v);
    19         v.pop_back();
    20     }
    21     
    22 private:
    23     vector<vector<int> > ret;
    24 };

    Method III

    递归的第二种实现:

     1 class Solution {
     2 public:
     3     vector<vector<int> > subsets(vector<int> &S) {
     4         sort(S.begin(), S.end());
     5         vector<int> v;
     6         ret.push_back(v);
     7         recursive(S, 0, v);
     8         return ret;
     9     }
    10     
    11     void recursive(vector<int> &S, int i, vector<int> &v) {
    12         if (i == S.size()) {
    13             return;
    14         }    
    15         
    16         for (int j = i; j < S.size(); ++j) {
    17             v.push_back(S[j]);
    18             ret.push_back(v);
    19             recursive(S, j + 1, v);
    20             v.pop_back();
    21         }
    22     }
    23     
    24 private:
    25     vector<vector<int> > ret;
    26 };

    Method IV

    网上有人用二进制运算。因为有n=S.size()个数,那么总共的子集数也就是1<<n,每个数的第k位相当于标志了第k个数是不是在该subset中。

    class Solution {
    public:
        vector<vector<int> > subsets(vector<int> &S) {
            sort(S.begin(), S.end());
            vector<vector<int> > ret;
            
            for (unsigned int i = 0; i < (1 << S.size()); ++i) {
                vector<int> v;
                for (int j = 0; j < S.size(); ++j) {
                    if (i >> j & 0x01) v.push_back(S[j]);
                }
                ret.push_back(v);
            }
            return ret;
        }
    };

     Subsets II

    Given a collection of integers that might contain duplicates, 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,2], a solution is:

    [
    [2],
    [1],
    [1,2,2],
    [2,2],
    [1,2],
    []
    ]

    Method I

    如果允许重复的话,如果仍用Method I,结果集会出现重复。比如S=[1,2,2,2],产生过程如下:

    []

    [1]

    [2][1,2]

    [2][1,2][2,2][1,2,2]

    [2][1,2][2,2][1,2,2][2,2,2][1,2,2,2]

    红色部分就重复了。观察到有这么一些规律:

    1. 如果S[i] != S[i - 1],那么和原来一样,结果集每一个subset都可以生成一个新的子集;

    2. 如果S[i] == S[i - 1],那么在处理S[i - 1]时生成了多少个子集,只用这些子集来生成新的子集。

    比如S[1] != S[0],所以结果集里面{[],[1]}都用来生成新子集{[2],[1,2]};

    S[2] == S[1],所以只用S[1]时生成的子集{[2],[1,2]}来生成新子集{[2,2],[1,2,2]};

    S[3]==S[2],所以只用S[2]时生成的子集{[2,2],[1,2,2]}来生成新子集{[2,2,2],[1,2,2,2]};这样就保证了不会重复;

    我用了一个count变量来记录需要用来生成新子集的旧子集个数;if S[i] != S[i - 1],那么count = ret.size(); 否则,count不变;

     1 class Solution {
     2 public:
     3     vector<vector<int> > subsetsWithDup(vector<int> &S) {
     4         vector<vector<int> > ret;
     5         vector<int> v;
     6         ret.push_back(v);
     7         sort(S.begin(), S.end());
     8         int count = 1;
     9         for(int i = 0; i < S.size(); ++i) {
    10             int n = ret.size();
    11             if (i > 0 && S[i - 1] != S[i]) {
    12                 count = n;
    13             } 
    14             for (int j = n - count; j < n; ++j) {
    15                 vector<int> nv(ret[j]);
    16                 nv.push_back(S[i]);
    17                 ret.push_back(nv);
    18             }
    19         }
    20         
    21         return ret;
    22     }
    23 };

     Method II

    仍用subset I 的MethodII的递归实现方式。主要是在去重。

    每碰到一个数,要么加进去,要么不加进去。最终产生所有集合。

    不加进去的逻辑是,如果检测到出现重复的数,就把后面的重复数都略过。这样对应于前面把2这个数加进去了,后面重复出现的2就略过了。

    加进去的逻辑是,无论重复与否,都要加进去,然后进去下一个数。

    class Solution {
    public:
        vector<vector<int> > subsetsWithDup(vector<int> &S) {
            sort(S.begin(), S.end());
            vector<int> v;
            recursive(S, 0, v);
            return ret;
        }
        
        void recursive(vector<int> &S, int i, vector<int> &v) {
            if (i >= S.size()) {
                ret.push_back(v);
                return;
            }
            int j = i + 1;
            while (j < S.size() && S[j] == S[j - 1]) j++;
            recursive(S, j, v);
            
            v.push_back(S[i]);
            recursive(S, i + 1, v);
            v.pop_back();
        }
        
    private:
        vector<vector<int> > ret;
    };

    MethodIII和MethodIV的修改网上都有。不过个人觉得递归的实现理解起来比较难。还是自己想出来的Method I好哈。。。。

  • 相关阅读:
    Windows 10 将MySQL5.5升级为MySQL5.7
    Django Rest Swagger生成api文档
    inception安装使用
    django 日志配置
    构建NTP时间服务器
    django 模型关系
    python 开发环境配置
    mongodb远程备份
    rest framework 尝鲜
    Django Rest Framework-介绍
  • 原文地址:https://www.cnblogs.com/linyx/p/3712893.html
Copyright © 2011-2022 走看看