Subsets系列

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 class Solution {
 2 public:
 3     vector<vector<int> > subsets(vector<int> &S) {
 4         sort(S.begin(), S.end());   //题目要求非递减,所以先排序
 5         vector<int> path;   //记录对数组元素的选择情况
 6         dfs(S, path, 0);
 7         return allpath;
 8     }
 9
10     void dfs(vector<int>& S, vector<int>& path, int k) {
11         if( k == S.size() ) {   //当k个元素都被选择完毕
12             allpath.push_back(path);    //那么这就是其中一个子集
13             return ;
14         }
15         dfs(S, path, k+1);  //不选择第k个元素
16         path.push_back(S[k]);   //放入path中
17         dfs(S, path, k+1);  //选择第k个元素
18         path.pop_back();    //取出
19     }
20
21 private:
22     vector< vector<int> > allpath;  //存放所有的子集
23 };

方法二:分析上面的dfs方法,如下图:

第一层是()

第二层是在第一层的基础上,每个元素都加上1,合起来就是(),(1)

第三层是是在第二层的基础上,每个元素都加上2,合起来就是(),(1),(2),(1,2)

第四层就是在第三层的基础上,每个元素都加上3,合起来就是(),(1),(2),(1,2),(3),(1,3),(2,3),(1,2,3)

因此迭代的方式容易得出了,代码如下:

 1 class Solution {
 2 public:
 3     vector<vector<int> > subsets(vector<int> &S) {
 4         vector< vector<int> > ans;
 5         sort(S.begin(), S.end());   //答案要求非递减,因此需要排序
 6         ans.push_back( vector<int>() ); //首先放入空集,此时ans存放得时第一层的结果
 7         for(int i=0; i<S.size(); ++i) { //迭代n个元素
 8             int presize = ans.size();   //标记上层的结果的个数
 9             for(int j=0; j<presize; ++j) {  //上层每个元素取出,并加上S[i],再放入下层的结果中,就得到了下层的结果
10                 vector<int> tv = ans[j];
11                 tv.push_back(S[i]);
12                 ans.push_back(tv);
13             }
14         }
15         return ans;
16     }
17 };

方法三:使用二进制来模拟子集,数组元素为123,那么010,表示1不选,2选,3不选,依次遍历二进制就可以获取原集合的所有子集,代码如下:

 1 class Solution {
 2 public:
 3     vector<vector<int> > subsets(vector<int> &S) {
 4         vector< vector<int> > ans;
 5         sort(S.begin(), S.end());   //答案要求非递减,因此需要排序
 6         int len = S.size();
 7         unsigned long long maxbits = 1<<len;    //设置二进制数上限
 8         while( --maxbits ) {    //遍历每个二进制值,然后在根据i位的值是1还是0,来选择还是不选择S[i]
 9             vector<int> tv;
10             for(int i=0; i<len; ++i)    //依次扫描n位
11                 if( 1<<i & maxbits ) {
12                     tv.push_back(S[i]);
13                 }
14             ans.push_back(tv);
15         }
16         ans.push_back( vector<int>() ); //maxbits为0跳出循环,没有放入空集,因此需要放入空集
17         return ans;
18     }
19 };

注:代码有bug,如果元素个数超过64个....那么就会出现异常,解决方案是开数组,模拟二进制进位。。。。

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

方法一:先按照无重复元素进行计算,然后在结果中去重,比较暴力。

方法二:分析1222数组子集生成流程,如下:

第一层为空集,第一层为()

第二层为在第一层基础上直接加1,第二层结果为(), (1)

第三层为在第二层基础上直接加2,第三层结果为(), (1), (2), (1,2)

第四层在第三层的基础上,挑选了(2),(1,2)加2,最后第四层为(), (1), (2), (1,2), (2,2),  (1,2,2)

第五层在第四层的基础上,挑选了(2,2), (1,2,2)加2, 最后第五层为(), (1), (2), (1,2), (2,2),  (1,2,2), (2,2,2), (1,2,2,2)

排序后,当前处理的数字在前面出现了k次,那么只能在已经出现k次该数的集合上添加该数

则递归的方法如下:

 1 class Solution {
 2 public:
 3     vector<vector<int> > subsetsWithDup(vector<int> &S) {
 4         sort(S.begin(), S.end());
 5         vector<int> path;
 6         ans.clear();
 7         dfs(S, path, 0);
 8         return ans;
 9     }
10
11     void dfs(vector<int>& S, vector<int>& path, int k) {
12         if( k == S.size() ) {
13             ans.push_back(path);
14             return ;
15         }
16         int presame = k;
17         while( presame >= 0 && S[presame] == S[k] ) --presame;  //往左边寻找第一个不同于S[k]元素
18         int samenum = k - presame - 1;  //在第k个数前面与S[k]相同元素的个数
19         if( samenum == 0    //若没有相同的元素
20             || ( path.size() >= samenum && path[path.size()-samenum] == S[k] )  //出现samenum个相同元素的集合
21             ) {
22             path.push_back(S[k]);   //那么选择S[k]
23             dfs(S, path, k+1);
24             path.pop_back();
25         }
26         dfs(S, path, k+1);  //不选择S[k]
27     }
28
29 private:
30     vector< vector<int> > ans;
31 };

迭代的方法如下:

 1 class Solution {
 2 public:
 3     vector<vector<int> > subsetsWithDup(vector<int> &S) {
 4         sort(S.begin(), S.end());
 5         vector< vector<int> > ans;
 6         ans.push_back( vector<int>() ); //放入空集
 7         int preInt = S[0]; //前一个被访问的元素
 8         int needSelectSubsets = 1;  //如果当前数组在前面出现k次,那么这个值表示含有k个相同元素的子集
 9         for(int i=0; i<S.size(); ++i) {
10             if( S[i] != preInt ) {  //如果不等,直接更新
11                 preInt = S[i];
12                 needSelectSubsets = ans.size();
13             }
14             int len = ans.size();
15             for(int j = len - needSelectSubsets; j<len; ++j) {  //ans中后面needSelectSubsets个子集满足添加元素条件
16                 vector<int> tv = ans[j];
17                 tv.push_back(S[i]);
18                 ans.push_back(tv);
19             }
20         }
21         return ans;
22     }
23 };

 

时间: 2024-11-06 12:12:55

Subsets系列的相关文章

Subsets 子集系列问题 leetcode

子集系列问题: Coding 问题中有时会出现这样的问题:给定一个集合,求出这个集合所有的子集(所谓子集,就是包含原集合中的一部分元素的集合). 或者求出满足一定要求的子集,比如子集中元素总和为定值,子集元素个数为定值等等. 我把它们归类为子集系列问题. leetcode上原题链接: 思路分析: 思路一 可以用递推的思想,观察S=[], S =[1], S = [1, 2] 时解的变化. 可以发现S=[1, 2] 的解就是 把S = [1]的所有解末尾添上2,然后再并上S = [1]里面的原有解

ISLR系列:(4.1)模型选择--- Subset Selection

Linear Model Selection and Regularization 此博文是 An Introduction to Statistical Learning with Applications in R 的系列读书笔记,作为本人的一份学习总结,也希望和朋友们进行交流学习. 该书是The Elements of Statistical Learning 的R语言简明版,包含了对算法的简明介绍以及其R实现,最让我感兴趣的是算法的R语言实现. [转载时请注明来源]:http://www

【一天一道LeetCode】#78. Subsets

一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given a set of distinct integers, nums, return all possible subsets. Note: Elements in a subset must be in non-descending order. The solution set must not co

[Aizu] ITP2_11_A~D: 子集的枚举系列

前言 ITP系列之使用位集枚举, 具体内容参见bitset PS: 感觉第三个与第四个拓展之后实用性较强 题目链接 ITP2_11_A: Enumeration of Subsets I ITP2_11_B: Enumeration of Subsets II ITP2_11_C: Enumeration of Subsets III ITP2_11_D: Enumeration of Combinations 求解 第一题 分析 要求n个数的组合, 组合内元素数量不限, 创建一个位集, 从0一

kubernetes系列教程(三)kubernetes快速入门

写在前面 kubernetes中涉及很多概念,包含云生态社区中各类技术,学习成本比较高,k8s中通常以编写yaml文件完成资源的部署,对于较多入门的人来说是个较高的门坎,本文以命令行的形式代理大家快速入门,俯瞰kubernetes核心概念,快速入门. 1. 基础概念 1.1 集群与节点 kubernetes是一个开源的容器引擎管理平台,实现容器化应用的自动化部署,任务调度,弹性伸缩,负载均衡等功能,cluster是由master和node两种角色组成,其中master负责管理集群,master节

【Windows10&nbsp;IoT开发系列】配置篇

原文:[Windows10 IoT开发系列]配置篇 Windows10 For IoT是Windows 10家族的一个新星,其针对不同平台拥有不同的版本.而其最重要的一个版本是运行在Raspberry Pi.MinnowBoard和Galileo平台上的核心版.本文重点针对Raspberry Pi平台的Windwos10 IoT配置做介绍. Windows 10 IoT Editions ​一:设置你的电脑. 注:​开发Windows10 IoT的电脑需要Visual Studio 2015.

【Windows10&nbsp;IoT开发系列】PowerShell的相关配置

原文:[Windows10 IoT开发系列]PowerShell的相关配置 可使用 Windows PowerShell 远程配置和管理任何 Windows 10 IoT 核心版设备.PowerShell 是基于任务的命令行 Shell 和脚本语言,专为进行系统管理而设计. 1.​启动 PowerShell (PS) 会话 注:若要使用装有Windows10 IoT Core设备启动PS会话,首先需要在主机电脑与设备之间创建信任关系. ​启动 Windows IoT 核心版设备后,与该设备相连的

【Windows10&nbsp;IoT开发系列】API&nbsp;移植工具

原文:[Windows10 IoT开发系列]API 移植工具 Windows 10 IoT Core 中是否提供你的当前 Win32 应用程序或库所依赖的 API? 如果不提供,是否存在可使用的等效 API? 此工具可以为你回答这些问题,并协助你将你的当前 Win32 应用程序和库迁移到 Windows IoT Core. Windows 10 IoT 核心版 API 移植工具可在 ms-iot/iot-utilities github 存储库中找到.下载存储库 zip 并将 IoTAPIPor

【Windows10&nbsp;IoT开发系列】“Hello,World!”指导

原文:[Windows10 IoT开发系列]"Hello,World!"指导 本文主要是介绍使用C#来开发一个可以运行在Raspberry Pi2上的一个基本项目. ​1.在启动Visual Studio 2015后,选择"文件"→"新建项目". ​在打开的"新建项目"对话框中,选择"通用". ​选择第一个项目"空白应用(通用Windows)" 新建项目 ​注:如果这是你创建的第一个项