【leetcode】Subsets (Medium) ☆
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.
就是找出数字的全部子集。
我的思路:
设输入是 1 2 3 4
先把输入从小到大排序
长度 0 : []
长度 1 : 把输入数据从第一个数开始 1, 找上一个数字结果中开始数字比1大的解 没有 直接压入 [1]
2,找上一个数字结果中开始数字比2大的解 没有 直接压入 [2]
...
得到长度为1的解是 [1] [2] [3] [4]
长度 2 : 把输入数据从第一个数开始 1, 找上一个数字结果中开始数字比1大的解 有[2] [3] [4], 压入[1 2][1 3][1 4]
2, 找上一个数字结果中开始数字比2大的解 有 [3] [4], 压入[2 3][2 4]
...
得到长度为2的解是 [1 2][1 3][1 4][2 3][2 4][3 4]
长度 3 : 把输入数据从第一个数开始 1, 找上一个数字结果中开始数字比1大的解 有[2 3][2 4][3 4], 压入[1 2 3][1 2 4][1 3 4]
2, 找上一个数字结果中开始数字比2大的解 有 [3 4], 压入[2 3 4]
得到长度为3的解是 [1 2 3][1 2 4][1 3 4][2 3 4]
长度 4 : 把输入数据从第一个数开始 1, 找上一个数字结果中开始数字比1大的解 有[2 3 4], 压入[1 2 3 4]
2, 找上一个数字结果中开始数字比2大的解 没有
得到长度为4的解是 [1 2 3 4]
代码用了posfirst,poslast来表示上一个长度答案的范围。
class Solution { public: vector<vector<int> > subsets(vector<int> &S) { sort(S.begin(), S.end()); vector<vector<int>> ans; vector<int> partans; ans.push_back(partans); //空的 int posfirst = 0; //上一个长度子集在ans中的起始下标 int poslast = 0; //上一个长度子集在ans中的结束下标 for(int len = 1; len <= S.size(); len++) //对长度循环 { poslast = ans.size() - 1; for(int i = 0; i < S.size(); i++) //对起始数字循环 { while(!ans[posfirst].empty() && S[i] >= ans[posfirst][0] && posfirst <= poslast) //跳过上一个长度答案中起始数字小于等于当前起始数字的解 { posfirst++; } for(int pos = posfirst;pos <= poslast; pos++) //获取当前的答案 { partans.push_back(S[i]); //压入当前数字 for(int j = 0; j < ans[pos].size(); j++) //压入上一个长度答案中的数字 { partans.push_back(ans[pos][j]); } ans.push_back(partans); partans.clear(); } } posfirst = poslast + 1; } return ans; } };
大神的解法:https://oj.leetcode.com/discuss/9213/my-solution-using-bit-manipulation
class Solution { public: vector<vector<int> > subsets(vector<int> &S) { sort (S.begin(), S.end()); int elem_num = S.size(); int subset_num = pow (2, elem_num); vector<vector<int> > subset_set (subset_num, vector<int>()); for (int i = 0; i < elem_num; i++) for (int j = 0; j < subset_num; j++) if ((j >> i) & 1) subset_set[j].push_back (S[i]); return subset_set; } };
解释如下:
This is an amazing solution.Learnt a lot.Let me try to explain this to those who didn't get the logic. Number of subsets for {1 , 2 , 3 } = 2^3 . why ? case possible outcomes for the set of subsets 1 -> Take or dont take = 2 2 -> Take or dont take = 2 3 -> Take or dont take = 2 therefore , total = 2*2*2 = 2^3 = { { } , {1} , {2} , {3} , {1,2} , {1,3} , {2,3} , {1,2,3} } Lets assign bits to each outcome -> First bit to 1 , Second bit to 2 and third bit to 3 Take = 1 Dont take = 0 0) 0 0 0 -> Dont take 3 , Dont take 2 , Dont take 1 = { } 1) 0 0 1 -> Dont take 3 , Dont take 2 , take 1 = {1 } 2) 0 1 0 -> Dont take 3 , take 2 , Dont take 1 = { 2 } 3) 0 1 1 -> Dont take 3 , take 2 , take 1 = { 1 , 2 } 4) 1 0 0 -> take 3 , Dont take 2 , Dont take 1 = { 3 } 5) 1 0 1 -> take 3 , Dont take 2 , take 1 = { 1 , 3 } 6) 1 1 0 -> take 3 , take 2 , Dont take 1 = { 2 , 3 } 7) 1 1 1 -> take 3 , take 2 , take 1 = { 1 , 2 , 3 } In the above logic ,Insert S[i] only if (j>>i)&1 ==true { j E { 0,1,2,3,4,5,6,7 } i = ith element in the input array } element 1 is inserted only into those places where 1st bit of j is 1 if( j >> 0 &1 ) ==> for above above eg. this is true for sl.no.( j )= 1 , 3 , 5 , 7 element 2 is inserted only into those places where 2nd bit of j is 1 if( j >> 1 &1 ) == for above above eg. this is true for sl.no.( j ) = 2 , 3 , 6 , 7 element 3 is inserted only into those places where 3rd bit of j is 1 if( j >> 2 & 1 ) == for above above eg. this is true for sl.no.( j ) = 4 , 5 , 6 , 7 Time complexity : O(n*2^n) , for every input element loop traverses the whole solution set length i.e. 2^n