78. Subsets&集合的子集&Power Set
2014-03-05 11:49
405 查看
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 =
is:
这个问题编程实现就是不会,看了别人的答案,想了半天,微微懂点儿。
请编写一个方法,返回某集合的所有非空子集。
给定一个int数组A和数组的大小int n,请返回A的所有非空子集。保证A的元素个数小于等于20,且元素互异。各子集内部从大到小排序,子集之间字典逆序排序,见样例。
测试样例:
首先,对时间复杂度和空间复杂度进行评估。
一个集合会有多少个子集?生成一个子集时,每个元素都可以“选择”在或不在这个子集中。也就是说,第一个元素有两种选择:它要么在集合中,要么不在集合中。同样,第二个元素也有两个选择,依此类推,共有
个子集。因此,在时间或空间复杂度上,不可能比
更好。
集合
的所有子集组成的集合称为幂集,用符号表示为:
或者
。
解法1:递归
这道题非常适合简单构造法。假设我们正尝试找出集合
的所有子集,可以从终止条件开始。
终止条件n=0
空集合只有一个子集
情况:n=1
集合
有两个子集,
和
情况:n=2
集合
有四个子集:
,
,
,
情况:n=3
我们需要找出一种方法,根据之前的答案产生n=3时的答案。
比较n=3和n=2时的结果,可以看到
=
,
,
,
=
,
,
,
,
,
,
,
二者的不同之处在于,所有含有
的子集,
都没有。
所以,是需要复制
里的子集,并在这些子集中添加
,然后将二者合并在一起,就可以得到
。
情况:n>0
要求
,先求
,结果复制一份,并在每个复制后的集合中加入
。
这个方法的时间和空间复杂度都是。
解法2:组合数学
注意当我们在产生一个集合时,对每一个元素我们有两种选择:(1)元素在集合中(“YES”状态)或者(2)元素不在集合中(“NO”状态)。这意味着,每一个子集是一个yes/no的集合,例如“YES,YES,NO,NO,YES,NO”。
这样我们可以得到个可能的集合。对所有元素,我们怎样可以迭代访问所有可能的“YES/NO”状态序列?每个“YES”可以被当作1,每个“NO”可以被当作0,那么每个子集合就可以被表示为一个二进制串。
要产生所有子集合就转换成产生所有的二进制数字(也就是,所有的整数。)
我们迭代访问从0到(不包括)的所有数字,并将二进制表示转换成一个集合。
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], [] ]
class Solution { public: vector<vector<int>> subsets(vector<int>& nums) { sort(nums.begin(),nums.end()); vector<vector<int>> ret; vector<int> cur; subsetsCore(nums,cur,ret,0); return ret; } void subsetsCore(vector<int>&nums,vector<int>& cur,vector<vector<int>>& ret,int begin) { ret.push_back(cur); for(int i = begin;i<nums.size();++i) { if(i==begin || nums[i] != nums[i-1]) { cur.push_back(nums[i]); subsetsCore(nums,cur,ret,i+1); cur.pop_back(); } } } };
这个问题编程实现就是不会,看了别人的答案,想了半天,微微懂点儿。
class Solution { public: vector<vector<int>> subsets(vector<int> &S) { vector<vector<int>> ret; vector<int> cur; sort(S.begin(),S.end()); subsets(S,0,cur,ret); return ret; } void subsets(vector<int> &S,int step,vector<int> &cur,vector<vector<int>> &ret) { if(step == S.size()) { ret.push_back(cur); return; } //不选择S[step] subsets(S,step+1,cur,ret); //选择S[Step] cur.push_back(S[step]); subsets(S,step+1,cur,ret); cur.pop_back(); } };
题目描述
请编写一个方法,返回某集合的所有非空子集。给定一个int数组A和数组的大小int n,请返回A的所有非空子集。保证A的元素个数小于等于20,且元素互异。各子集内部从大到小排序,子集之间字典逆序排序,见样例。
测试样例:
[123,456,789]
返回:{[789,456,123],[789,456],[789,123],[789],[456 123],[456],[123]}
首先,对时间复杂度和空间复杂度进行评估。
一个集合会有多少个子集?生成一个子集时,每个元素都可以“选择”在或不在这个子集中。也就是说,第一个元素有两种选择:它要么在集合中,要么不在集合中。同样,第二个元素也有两个选择,依此类推,共有
个子集。因此,在时间或空间复杂度上,不可能比
更好。
集合
的所有子集组成的集合称为幂集,用符号表示为:
或者
。
解法1:递归
这道题非常适合简单构造法。假设我们正尝试找出集合
的所有子集,可以从终止条件开始。
终止条件n=0
空集合只有一个子集
情况:n=1
集合
有两个子集,
和
情况:n=2
集合
有四个子集:
,
,
,
情况:n=3
我们需要找出一种方法,根据之前的答案产生n=3时的答案。
比较n=3和n=2时的结果,可以看到
=
,
,
,
=
,
,
,
,
,
,
,
二者的不同之处在于,所有含有
的子集,
都没有。
所以,是需要复制
里的子集,并在这些子集中添加
,然后将二者合并在一起,就可以得到
。
情况:n>0
要求
,先求
,结果复制一份,并在每个复制后的集合中加入
。
class Subset { public: vector<vector<int> > getSubsets(vector<int> A, int n) { vector<vector<int> > ret = getSubsets(A,n,n); for(vector<vector<int>>::iterator iter=ret.begin(); iter!=ret.end(); ) { if( (*iter).empty()) iter = ret.erase(iter); else iter ++ ; } return ret; } vector<vector<int> > getSubsets(vector<int> A, int n,int index) { vector<vector<int>> allSubsets; if (index == 0) { vector<int> nullSubSet; allSubsets.push_back(nullSubSet); return allSubsets; } else { vector<vector<int>> moreSubsets = getSubsets(A,n,index-1); vector<vector<int>> copyOfMoreSubsets(moreSubsets); int value = A[index-1]; for(vector<vector<int>>::iterator it = moreSubsets.begin();it!= moreSubsets.end();++it) { (*it).push_back(value); allSubsets.push_back(*it); } for(vector<vector<int>>::iterator it = copyOfMoreSubsets.begin();it!= copyOfMoreSubsets.end();++it) { allSubsets.push_back(*it); } for(vector<vector<int>>::iterator it = allSubsets.begin();it!= allSubsets.end();++it) { sort((*it).begin(),(*it).end(),greater<int>()); } return allSubsets; } } };
这个方法的时间和空间复杂度都是。
解法2:组合数学
注意当我们在产生一个集合时,对每一个元素我们有两种选择:(1)元素在集合中(“YES”状态)或者(2)元素不在集合中(“NO”状态)。这意味着,每一个子集是一个yes/no的集合,例如“YES,YES,NO,NO,YES,NO”。
这样我们可以得到个可能的集合。对所有元素,我们怎样可以迭代访问所有可能的“YES/NO”状态序列?每个“YES”可以被当作1,每个“NO”可以被当作0,那么每个子集合就可以被表示为一个二进制串。
要产生所有子集合就转换成产生所有的二进制数字(也就是,所有的整数。)
我们迭代访问从0到(不包括)的所有数字,并将二进制表示转换成一个集合。
class Solution { public: std::vector<std::vector<int> > subsets(std::vector<int> &A) { vector<vector<int> > ret; int max = 1<<A.size();/*compute 2^n*/ for (int i = 0;i<max;++i) { vector<int> subset = convertIntToSet(A,i); ret.push_back(subset); } return ret; } private: vector<int> convertIntToSet(const vector<int>& A,int num) { vector<int> ret; int index = 0; for(int i = num;i>0;i>>=1) { if((i&1) == 1) ret.push_back(A[index]); ++index; } return ret; } };
相关文章推荐
- leetcode解题之 77. Combinations&78. Subsets&90. Subsets II java 版(求所有子集)
- 输出一个集合所有子集的元素和(Print sums of all subsets of a given set)
- 78. Subsets && 90. Subsets II
- 78. Subsets && 90. Subsets II
- Java——集合框架之Set&HashSet,HashMap,泛型,compareTo
- subsets之给定一个数列&生成该数列所有的子集&升序
- 黑马程序员_java集合(1) Collection & List & Set & Map
- 78. Subsets & 90. Subsets II
- NSSet -- 集合&&NSMutableSet -- 可变集合
- STL:集合#include <set>
- 集合框架(四)——Collection 子集 ——————Set及其 小弟们!
- LeetCode--Subsets(集合的子集)Python
- 两种回溯方法解决子集问题的思路 leetcode 78. Subsets
- [leetcode 78 & 90, Medium] Subsets I and II
- 【Python】排列组合itertools & 集合set
- Java基础<十一>--->集合之List、Set
- <LeetCode OJ> 78 / 90 Subsets (I / II)
- python 从字典里取出内容,创建集合 dict -> set
- 集合框架(三) Set&HashSet
- Subsets(集合的子集)