LeetCode 题解(24): 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],
  []
]

题解:

做LeetCode以来碰到的第一个费解的题目。一直纠结于重复的问题。

以[1,1,2,2,3,3]为例:

思路: 用一个count记录上一次插入最终结果的子集个数,如最开始插入[],count = 1;第二次插入1,count = 1;

第三次插入第二个1时,发现pre == current (1 == 1),则只需result[result.size() - count]~result[result.size()-1]的子集中插入1,现在result中包含{[], [1]},result.size() - count = 1,则只需在[1]中插入1,得到result = {[],[1],[1,1]},count = 1。


继续插入下一个数:2. 因为pre != current (1 != 2),则在result的所有结果中插入2,得到result={[],[1],[1,1],[2], [1,2], [1,1,2]},count = 3。

继续插入下一个数:2. 因为pre == current (2 == 2),则只在result[result.size() - count]~result[result.size()-1]中插入2,即只在[2],[1,2],[1,1,2]中插入2。因为若在前0~result.size()-count个子集中插入2,就会造成重复。


循环S所用元素,并按上述规律插入到result相应的子集中去。

class Solution {
public:
    vector<vector<int> > subsetsWithDup(vector<int> &S) {
        vector<vector<int>> result;
        if(S.empty())
            return result;
            
        sort(S.begin(), S.end());
        
        vector<int> temp;
        result.push_back(temp);
        temp.push_back(S[0]);
        result.push_back(temp);
        
        int pre = S[0];
        int count = 1;
        
        for(int i = 1; i < S.size(); i++)
        {
            int start = 0;
            int end = result.size();
            if( S[i] == pre )
            {
                start = end - count;
            }
            count = 0;
            for(int j = start; j < end; j++)
            {
                temp = result[j];
                temp.push_back(S[i]);
                result.push_back(temp);
                count++;
            }
            pre = S[i];
        }
        
        return result;
    }
};

还有纠结了许久的递归解法,关键点是用一个额外数组记录S中每一位的访问情况。十分复杂,还是推荐上一种思路。

class Solution {
public:
    vector<vector<int> > subsetsWithDup(vector<int> &S) {
        vector<vector<int>> result;
        if(S.empty())
            return result;
            
        sort(S.begin(), S.end());
        
        vector<int> temp;
        vector<bool> visited(S.size(), false);
        result.push_back(temp);
        
        for(int i = 1; i <= S.size(); i++)
        {
            subsetsRecursion(result, S, temp, visited, i);//计算从长度1至长度S.size()的子集
        }
        
        return result;
    }
    
    void subsetsRecursion(vector<vector<int>> & result, vector<int> & S, vector<int> & temp, vector<bool> & visited, int length)
    {
        if(temp.size() == length) //递归结束的条件
        {
            result.push_back(temp);
            return;
        }
        
        for(int i = 0; i < S.size(); i++)
        {
            if(!visited[i]) //如果当前元素正在被访问,直接跳过,否则:
            {
                if(i >= 1 && S[i] == S[i-1] && !visited[i-1]) //若当前元素与前一个元素值相等,且前一个元素没有正在被访问,直接跳过,否则:
                    continue;
                else if(!temp.size() || temp.back() <= S[i]) //若当前中间结果不为空集,且当前中间结果的最后一个元素大于当前元素,直接跳过,否则:
                {
                    visited[i] = true;
                    temp.push_back(S[i]);
                    subsetsRecursion(result, S, temp, visited, length);
                    temp.pop_back();
                    visited[i] = false;
                }
            }
        }
    }
};



你可能感兴趣的:(Algorithm,LeetCode,II,Subsets)