求集合的所有子集问题

LeetCode:Subsets

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 = [1,2,3], a solution is:

[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
] 本文地址

分析:求集合的所有子集问题。题目要求子集中元素非递减序排列,因此我们先要对原来的集合进行排序。原集合中每一个元素在子集中有两种状态:要么存在、要么不存在。这样构造子集的过程中每个元素就有两种选择方法:选择、不选择,因此可以构造一颗二叉树,例如对于例子中给的集合[1,2,3],构造的二叉树如下(左子树表示选择该层处理的元素,右子树不选择),最后得到的叶子节点就是子集:

算法1:根据上面的启发,我们可以用dfs来得到树的所有叶子节点,代码如下:

 class Solution {
private:
vector<vector<int> >res;
public:
vector<vector<int> > subsets(vector<int> &S) {
// IMPORTANT: Please reset any member data you declared, as
// the same Solution instance will be reused for each test case.
//先排序,然后dfs每个元素选或者不选,最后叶子节点就是所有解
res.clear();
sort(S.begin(), S.end());
vector<int>tmpres;
dfs(S, , tmpres);
return res;
}
void dfs(vector<int> &S, int iend, vector<int> &tmpres)
{
if(iend == S.size())
{res.push_back(tmpres); return;}
//选择S[iend]
tmpres.push_back(S[iend]);
dfs(S, iend+, tmpres);
tmpres.pop_back();
//不选择S[iend]
dfs(S, iend+, tmpres);
}
};

算法2:从上面的二叉树可以观察到,当前层的集合 = 上一层的集合 + 上一层的集合加入当前层处理的元素得到的所有集合(其中树根是空集),因此可以从第二层开始(第一层是空集合)迭代地求最后一层的所有集合(即叶子节点),代码如下:

 class Solution {
public:
vector<vector<int> > subsets(vector<int> &S) {
// IMPORTANT: Please reset any member data you declared, as
// the same Solution instance will be reused for each test case.
int len = S.size();
sort(S.begin(), S.end());
vector<vector<int> > res();//开始加入一个空集
for(int i = ; i < len; ++i)
{
int resSize = res.size();
for(int j = ; j < resSize; j++)
{
res.push_back(res[j]);
res.back().push_back(S[i]);
}
}
return res;
}
};

算法3:可以根据二进制的思想,比如对于3个元素的集合,000表示一个元素都不选择,001表示选择第一个元素,101表示选择第一个和第三个元素...。因此如果集合大小为n,我们只需要让一个整数从0逐渐增加到2^n-1, 每个整数的二进制形式可以表示一个集合。如果用整数的二进制表示集合,这个算法有个限制,最大能表示集合元素的个数为64(unsigned long long)。如果使用bitmap,然后模拟二进制的加1操作,则对集合大小就没有限制。刚好这一题集合的大小不超过64

 class Solution {
public:
vector<vector<int> > subsets(vector<int> &S) {
// IMPORTANT: Please reset any member data you declared, as
// the same Solution instance will be reused for each test case.
int len = S.size();
sort(S.begin(), S.end());
vector<vector<int> > res();//开始加入一个空集 unsigned long long bit = , bitmax = (<<len);
vector<int> tmpres;
while(bit < bitmax)
{
tmpres.clear();
unsigned long long curBit = bit;
for(int i = ; i < len; i++)//依次检测前len个二进制位
{
if(curBit & )
tmpres.push_back(S[i]);
curBit >>= ;
}
res.push_back(tmpres);
bit++;
}
return res;
}
};

LeetCode: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],
[]
]

分析:在上一题的基础上,可以允许集合中包含重复元素,我们也把相应的二叉树画出类,以集合{1,2,2}举例

算法1:dfs解法。注意到处理第三个元素2时,因为前面已经处理了一次2,所有第三层中,我们只在已经添加过2的集合{1,2}、{2}上再添加2,而没有在集合{1}, {}上添加2(画叉叉的那么分支),假设下面还有一个2,那么我们只在第四层的包含两个2的集合{1,2,2}、{2,2}上再添加2,其它都不添加。因此dfs时,如果当前处理的数字前面出现了k次,那么我们要处理的集合中必须包含k个该元素。代码如下:

 class Solution {
private:
vector<vector<int> >res;
public:
vector<vector<int> > subsetsWithDup(vector<int> &S) {
// IMPORTANT: Please reset any member data you declared, as
// the same Solution instance will be reused for each test case.
//先排序,然后dfs每个元素选或者不选,最后叶子节点就是所有解
res.clear();
sort(S.begin(), S.end());
vector<int>tmpres;
dfs(S, , tmpres);
return res;
}
void dfs(vector<int> &S, int iend, vector<int> &tmpres)
{
if(iend == S.size())
{res.push_back(tmpres); return;}
int firstSame = iend;
while(firstSame >= && S[firstSame] == S[iend])firstSame--;
firstSame++; //firstSame是第一个和S[iend]相同数字的位置
int sameNum = iend - firstSame;//和S[iend]相同数字的个数(除自己)
if(sameNum == ||
(tmpres.size() >= sameNum && tmpres[tmpres.size() - sameNum] == S[iend]))
{
//选择S[iend]
tmpres.push_back(S[iend]);
dfs(S, iend+, tmpres);
tmpres.pop_back();
}
//不选择S[iend]
dfs(S, iend+, tmpres);
}
};

算法2:在上一题算法2的基础上,如果当前处理的元素没有出现过,则把前面得到的所有集合加上该元素;如果出现过,则只把上一轮处理的集合加上该元素。比如处理第二个2时(二叉树第三层),我们只把上一轮添加过数字的集合{1,2}、{2}再添加一个2加入结果中,{1}、{}是从上一层直接继承下来的,所以不作处理。代码如下:

 class Solution {
private:
vector<vector<int> >res;
public:
vector<vector<int> > subsetsWithDup(vector<int> &S) {
// IMPORTANT: Please reset any member data you declared, as
// the same Solution instance will be reused for each test case.
int len = S.size();
sort(S.begin(), S.end());
vector<vector<int> > res();//开始加入一个空集
int last = S[], opResNum = ;//上一个数字、即将要进行操作的子集数量
for(int i = ; i < len; ++i)
{
if(S[i] != last)
{
last = S[i];
opResNum = res.size();
}
//如果有重复数字,即将操作的子集的数目和上次相同
int resSize = res.size();
for(int j = resSize-; j >= resSize - opResNum; j--)
{
res.push_back(res[j]);
res.back().push_back(S[i]);
}
}
return res;
}
};

上一题基于二进制思想的算法3不适合于包含重复元素的集合

【版权声明】转载请注明出处:http://www.cnblogs.com/TenosDoIt/p/3451902.html

LeetCode:Subsets I II的更多相关文章

  1. LeetCode Subsets I& II——递归

    I Given a set of distinct integers, S, return all possible subsets. Note: Elements in a subset must ...

  2. LeetCode Subsets II (DFS)

    题意: 给一个集合,有n个可能相同的元素,求出所有的子集(包括空集,但是不能重复). 思路: 看这个就差不多了.LEETCODE SUBSETS (DFS) class Solution { publ ...

  3. LeetCode Subsets (DFS)

    题意: 给一个集合,有n个互不相同的元素,求出所有的子集(包括空集,但是不能重复). 思路: DFS方法:由于集合中的元素是不可能出现相同的,所以不用解决相同的元素而导致重复统计. class Sol ...

  4. 子集系列(一) 传统subset 问题,例 [LeetCode] Subset, Subset II, Bloomberg 的一道面试题

    引言 Coding 问题中有时会出现这样的问题:给定一个集合,求出这个集合所有的子集(所谓子集,就是包含原集合中的一部分元素的集合). 或者求出满足一定要求的子集,比如子集中元素总和为定值,子集元素个 ...

  5. Subsets I&&II——经典题

    Subsets I Given a set of distinct integers, nums, return all possible subsets. Note: Elements in a s ...

  6. [LeetCode] Palindrome Partitioning II 解题笔记

    Given a string s, partition s such that every substring of the partition is a palindrome. Return the ...

  7. [leetcode]Word Ladder II @ Python

    [leetcode]Word Ladder II @ Python 原题地址:http://oj.leetcode.com/problems/word-ladder-ii/ 参考文献:http://b ...

  8. LeetCode:课程表II【210】

    LeetCode:课程表II[210] 题目描述 现在你总共有 n 门课需要选,记为 0 到 n-1. 在选修某些课程之前需要一些先修课程. 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一 ...

  9. LeetCode:全排列II【47】

    LeetCode:全排列II[47] 参考自天码营题解:https://www.tianmaying.com/tutorial/LC47 题目描述 给定一个可包含重复数字的序列,返回所有不重复的全排列 ...

随机推荐

  1. jQuery获取Table-Input控件值封装

  2. JavaScript学习笔记7 之DOM文档对象模型

    一.什么是DOMDocument Object Model 文档 -------对象 ----模型-------缩写DOM DOM是针对HTML和XML文档的一个API(应用程序编程接口).DOM描绘 ...

  3. Introduction to Microsoft Dynamics 365 licensing

    Microsoft Dynamics 365 will be released on November 1. In preparation for that, Scott Guthrie hosted ...

  4. SharePoint 2013 图文开发系列之应用程序页

    在SharePoint中,有两种页面类型,一种是保存在数据库中的页面,我们可以在网站的页面库中看到:还有一种叫做应用程序页,部署在服务器上,Layouts下面的页面,是应用程序页,主要是完成特定功能的 ...

  5. RoboGuice 3.0 (三)总结篇

    经过前两篇的介绍,我们了解了如何使用RoboGuice方便的为我们注入需要的对象,这篇将着重说明原理. 一.Guice与RoboGuice Guise是Google开发的一个轻量级的依赖注入框架,主要 ...

  6. iOS开发之聊天模块--内容保存逻辑实现

    需求详解: 在实际开发中,有可能是在后期优化的时候,会有这么需要优化的需求:聊天输入框保存之前输入的文本,提高用户的良好体验. 在聊天模块中,用户可能会在输入框输入若干字符,但是没有点击发送就点击退出 ...

  7. Linux-1:安装&忘记密码&CRT连接centos 6.5

    我是在虚拟机VM安装的centos 6.5 一.Linux安装 Ctrl + Alt:鼠标退出LINUX界面 安装我是参考,当然也可以根据网上教程安装:http://oldboy.blog.51cto ...

  8. Play Framework 完整实现一个APP(六)

    需要为Blog添加 查看和发表评论的功能 1.创建查看功能 Application.java中添加 show() 方法 public static void show(Long id) { Post ...

  9. IIS7如何部署asp.net网站

      第一步:发布网站 右键asp.net web项目,选择发布, 然后新建配置文件名称并选择 "文件系统" 发布方法. 目标位置选择本地新建的文件夹如: IISWebSite 第二 ...

  10. JDBC API Description

    package java.sql description What the JDBCTM 4.2 API Includes Versions What the java.sql Package Con ...