LeetCode(90)Subset 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],
  []
]

分析如下:

和上一题基本一样,区别在于这道题目的输入集合中的元素可能有重复,要求输出的子集合中过滤掉重复。可以先得到一个有重复的结果,再用个set或者hash滤重(使用0(N)空间复杂度)

我的代码:

第一版本,先迭代再滤重版本

// 先迭代再滤重
class Solution {
public:
    vector<vector<int> > subsetsWithDup(vector<int> &S) {
        int length=(int)S.size();
        vector<vector<int>> res(1);
        if(length==0)
            return res;
        std::sort(S.begin(), S.end());
        for(int i=0;i<S.size();++i){
            int j=(int)res.size();
            while(--j>=0){
                res.push_back(res[j]);
                res.back().push_back(S[i]);
            }
        }
        set<vector<int> > filter_set;
        for(int i=0;i<res.size();++i)
            filter_set.insert(res[i]);
        res.clear();
        for(set<vector<int> >::iterator it=filter_set.begin();it!=filter_set.end();it++)
            res.push_back(*it);
        return res;
    }
};


第二版本,先递归再滤重版本

//先递归再滤重
class Solution {
public:
        set<vector<int> > subsets_(vector<int> &S, int i){
        if(i==-1){
            vector<int> set_tmp;
            set<vector<int> > set_set_tmp;
            set_set_tmp.insert(set_tmp);
            return set_set_tmp;
        }
        set<vector<int> >  set_vec_tmp = subsets_(S,i-1);
        set<vector<int> >  set_vec_out = set_vec_tmp;
        set<vector<int> >::iterator set_vec_it=set_vec_tmp.begin();
        for(set_vec_it=set_vec_tmp.begin();set_vec_it!=set_vec_tmp.end();set_vec_it++){
            vector<int> vec_tmp=*set_vec_it;
            vec_tmp.push_back(S[i]);
            std::sort(vec_tmp.begin(),vec_tmp.end());
            set_vec_out.insert(vec_tmp);
        }
        return set_vec_out;
    }
    vector<vector<int> > subsetsWithDup(vector<int> &S) {
        int length=(int)S.size();
        vector<vector<int>> res;
        set<vector<int>> tmp;
        if(length==0)
            return res;
        length--;
        tmp=subsets_(S,length);
        for(set<vector<int> >::iterator it=tmp.begin();it!=tmp.end();it++){
            vector<int> small_vec=*it;
            res.push_back(small_vec);
        }
        return res;
    }
};


第三版本

我还没怎么看懂,不使用set不使用hash直接滤重,官网上看到的答案如下。

//不使用set或者hash直接滤重
class Solution {
public:
    vector<vector<int> > subsetsWithDup(vector<int> &S) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function            
        vector<int> path;
        vector<vector<int> > result;

        sort(S.begin(), S.end());
        sub(S, 0, path, result);
        return result;
    }

    void sub(vector<int> &s, int begin, vector<int> &path, vector<vector<int> > &result) {
        result.push_back(path);

        for (int i = begin; i < s.size(); ++i) {
            if (i != begin && s[i] == s[i - 1]) continue;

            path.push_back(s[i]);
            sub(s, i + 1, path, result);
            path.pop_back();
        }
    }
};

参考资料:

(1) http://discuss.leetcode.com/questions/253/subsets


update:  2014 - 12 - 17

在LeetCode(79) Subset 的不含重复元素的迭代版的思路上,回顾思路如下:

题目: If S = [1,2,3], return a solution of:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]

首先对S进行排序。

接下来进行subset的生成。

初始状态: []

第0次,加入S[0], 得到: [], [1]

第1次,加入S[1], 得到: [], [1], [2], [1, 2]

第2次,加入S[2], 得到: [], [1], [2], [1, 2], [3], [1,3], [2,3], [1,2,3]

从上面可以看出,

第0次->第1次,把S[1]加入到S[0]的每个subset中,形成新的subset(即[2], [1, 2]), 然后这堆新的subset和之前S[0]时候的那堆老的subset(即[], [1])一起构成新的结果(即  [], [1], [2], [1, 2])。

第1次->第2次,把S[2]加入到S[1]的每个subset中,形成新的subset(即[3], [1,3], [2,3], [1,2,3]), 然后这堆新的subset和之前S[1]时候的那堆老的subset(即[], [1], [2], [1,2])一起构成新的结果(即  [], [1], [2], [1, 2], [3], [1,3], [2,3], [1,2,3] )。

如果输入字符串S为长度更长的字符串,则重复上面这个过程直到把S的每个元素都加入了当前的集合。

然后,再看重复版本的迭代版本。 

If S = [1,2,2], a solution is:
[
  [2],
  [1],
  [1,2,2],
  [2,2],
  [1,2],
  []
]
首先对S进行排序。

接下来进行subset的生成。

第0次,填入S[0], 得到: [], [1]

第1次,填入S[1], 得到: [], [1], [2], [1,2]

第2次,填入S[2], 得到: [], [1], [2], [1,2], [2,2], [1,2,2]

可以看出来,在有重复输入的情况下,

第0次,因为没有重复输入,所以情况和没有重复版本的情况一样。

第1次,因为没有重复输入,所以情况和没有重复版本的情况一样。

第2次,因为有了重复输入(第2次的S[2] = 第1次的S[1] = 2),所以新生成的部分(第2次的绿色)只能从第1次的新生成部分(第1次的红色)产生,不能从第0次的产生。

下面,用this_layer记录当前这次的生成部分,这样,如果下次出现重复输入,就使用this_layer来生成新的部分。

class Solution {
public:
    vector<vector<int> > subsetsWithDup(vector<int> &S) {
          std::sort(S.begin(), S.end());
          vector<vector<int> > final(1);
          vector<vector<int> > this_layer;
          vector<int> every;
          int len = 0;
          for (int i = 0; i < S.size(); ++i) {
              if (i>0 && S[i] == S[i-1]) {
                  vector<vector<int> > this_layer_swap;
                  for (int j = 0; j < this_layer.size(); ++j) {
                      every = this_layer[j];
                      every.push_back(S[i]);
                      final.push_back(every);
                      this_layer_swap.push_back(every);
                  }
                  this_layer = this_layer_swap;
              } else {
                  len = final.size();
                  this_layer.clear();
                  for (int j = 0; j < len; ++j) {
                      every = final[j];
                      every.push_back(S[i]);
                      final.push_back(every);
                      this_layer.push_back(every);
                  }
              }
          }
          return final;
    }
};


update: 2015-03-24 删除了一个不必要的中间变量 vector<int> final.

//14ms 
class Solution {
public:
    vector<vector<int> > subsetsWithDup(vector<int> &S) {
          std::sort(S.begin(), S.end());
          vector<vector<int> > final(1);
          vector<vector<int> > this_layer;
          vector<vector<int> > next_layer;
          int len = 0;
          for (int i = 0; i < S.size(); ++i) {
              if (i>0 && S[i] == S[i-1]) {
                  next_layer.clear();        
                  for (int j = 0; j < this_layer.size(); ++j) {
                      final.push_back(this_layer[j]);
                      final.back().push_back(S[i]);
                      next_layer.push_back(final.back());
                  }
                  this_layer.swap(next_layer);
              } else {
                  len = final.size();
                  this_layer.clear();
                  for (int j = 0; j < len; ++j) {
                      final.push_back(final[j]);
                      final.back().push_back(S[i]);
                      this_layer.push_back(final.back());
                  }
              }
          }
          return final;
    }
};



你可能感兴趣的:(LeetCode,递归,迭代)