LintCode 17 子集
2017-02-18 20:09
211 查看
题目:subsets
要求:
给定一个含不同整数的集合,返回其所有的子集 注意事项 子集中的元素排列必须是非降序的,解集必须不包含重复的子集
样例:
如果 S = [1,2,3],有如下的解: [ [], [1], [1,2], [1,2,3], [1,3], [2], [2,3], [3] ]
算法要求:
你可以同时用递归与非递归的方式解决么?
解题思路:
集合中元素的个数为n,即有2^n个子集。下面这个算法是我从一位大神那里看到的,分享一下。讲一讲我的理解。我这个人一般理解一段代码,就喜欢输出中间的数据,看看代码运行的过程,让我带大家一起看一看这个算法运行的过程吧~,像我这么笨的一般就先理解,完了就死记硬背,某一天突然就想明白了~ 下面这个是{1,2}的子集生成过程 --------------- 第0次 j:0 k:0 子集存入成功 第1次 j:1 k:0 子集添加:1 j:0 k:1 子集存入成功 第2次 j:2 k:0 j:1 k:1 子集添加:2 j:0 k:2 子集存入成功 第3次 j:3 k:0 子集添加:1 j:1 k:1 子集添加:2 j:0 k:2 子集存入成功 --------------- j跟随着i变化,每次循环开始,j都会等于i。 再看一下j的变化过程(j/=2) 第一次:1~0 第二次:2~1~0 第三次:3~1~0 而且仅当j为奇数的时候才将nums[k]添加,注意这里的k每次都自增1 接着代入k来看一下(括号内为进行添加操作时k的值) 第一次:1(0)~0 第二次:2~1(1)~0 第三次:3(0)~1(1)~0 如果有第四次,那么是不是应该这样:4~2~1(2)~0 第五次:5(0)~2~1(2)~0 发现没有,这位大神巧妙的利用了操作符 "<<" 的机理,这样的话,从0~n,j值(奇数)与k值之间的关系就巧妙的变成了子集的关系,类似于排列组合。 注意每一次的结尾都为1~0,但是1的时候k的值可能不一样,就是从第1次~第3次相当于一个循环,第2次~第4次又是一个循环,环环扣,这样就不会出现重复的情况。 接着看一下代码理解一下。
算法如下:
vector<vector<int> > subsets(vector<int> &nums) { vector<vector<int> > vecs; int n = 1 << nums.size(); int j = 0; int k = 0; for (int i = 0; i < n; i++) { j = i; k = 0; vector<int> vec; while (j) { if (j & 1) { // 这句话相当于j % 2 == 1 vec.push_back(nums[k]); } j >>= 1; // 这句话相当于j /= 2; k++; } vecs.push_back(vec); } return vecs; }
相关文章推荐
- LintCode-----17.带重复元素的子集
- LintCode每日一练-限制条件子集
- lintcode&九章算法——Lintcode No.17 子集 ? 待解决
- LintCode 17. 子集
- lintcode 中等题:subSets 子集
- Lintcode 17 Subsets
- LintCode:子集
- lintcode之不同子序列数 + 序列II
- LintCode 6.合并排序数组 II
- LintCode "Coins in a Line II" !
- LintCode:有效数字
- lintcode Convert BST to Greater Tree
- lintcode:组成最大的数
- lintcode:恢复IP地址
- lintcode:First Position of Target
- lintcode:Sliding Window Maximum
- LintCode-剑指Offer-(12)带最小值操作的栈
- LintCode-最长无重复字符的子串
- LintCode:图中两个点之间的路线
- LintCode:整数转罗马数字