题目:
Given a collection of integers that might contain duplicates,S, return all possible subsets.
Note:
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; } } } } };