一、题目:
简化:编写一个方法,返回int数组的所有非空子集。
(有n个元素的集合的子集个数:2^n - 1)

二、思路及代码
思路一:递归
对每个元素,都可以选择进入或者不进入子集。
因此,求n个元素的子集,可以分解成:求出n-1个元素的子集A后,第n个元素再选择加入或者不加入A,得到最终子集。
求第n-1个元素的子集,可以递归求出n-2个元素的子集,再对第n-1个元素选择加入或者不加入,得到n-1个元素的子集。
……
……
第1个元素的子集,就是对第0个元素的子集即空集,选择加入或者不加入,得到自身和空集。

/*** way01——递归(增量构造法)*      含空集,需在main()去空集* @param arr 数组* @param n 构造增量n,获取前n个元素的子集* @return*/private static Set<Set<Integer>> subSet01(int[] arr,int n) {Set<Set<Integer>> obj = new HashSet<>();if (n == 1) {//获取第一个元素的子集:自身、空集Set<Integer> nil = new HashSet<>();//空集Set<Integer> temp = new HashSet<>();//装自身temp.add(arr[n-1]);obj.add(temp);obj.add(nil);return obj;}Set<Set<Integer>> toObj = subSet01(arr,n-1);//获取前n-1个元素的子集for (Set<Integer> s : toObj) {obj.add(s);//第n个元素不加进当前集合元素
//            !!注:这里需克隆。set是引用传递,直接加会影响上一步。而set自身的clone()是封闭的,需转为HashSet,用HashSet的clone()Set<Integer> clone = (Set<Integer>)((HashSet)s).clone();//第n个元素加进当前集合元素clone.add(arr[n-1]);obj.add(clone);}return obj;}

思路二:迭代
迭代就是把递归反向翻译过来,但迭代比递归在空间和时间上都更加优化。因为递归每一次调用自身时,都会新建一个栈空间去存放这个方法的临时变量。

/*** way02——迭代(逐步生成法)*      含空集,需在main()去空集* @param arr* @param n* @return*/private static Set<Set<Integer>> subSet02(int[] arr,int n) {Set<Set<Integer>> obj = new HashSet<>();Set<Integer> nil = new HashSet<>();
//        1、初始化为空集obj.add(nil);
//        2、遍历数组,嵌套obj,对每个obj元素选择进或不进for (int i = 0; i < n; i++) {Set<Set<Integer>> temp = new HashSet<>();//临时存储当前第i+1个的子集temp.addAll(obj);//不加当前元素,把上一次集合中的每个子集都加入for (Set<Integer> set : obj) {//遍历obj集合,把当前元素加进每个子集Set<Integer> clone = (Set) ((HashSet) set).clone();//注意克隆clone.add(arr[i]);temp.add(clone);}obj = temp;//更新}return obj;}

思路三:二进制解法
对于n个元素,都有选和不选的两种结果,那么这些结果可构成一个二叉选择树。如图示。
由此,求n个元素的所有非空子集,可利用1——2^n - 1的二进制(n位)表示每个元素的选择情况。
每个子集用set盛装,若二进制第i位==1则往set集合中添加进第i个元素;若为0,则不加入该元素。

/*** 二进制解法——最优*      不含空集* @param arr* @return*/public static Set<Set<Integer>> subSet03(int[] arr) {Set<Set<Integer>> set = new HashSet<>();
//        1、从 1—— 2^n-1遍历每一位数,即每一种子集组合for (int i = 1; i < (int)Math.pow(2,arr.length); i++) {//            遍历该数的二进制位,构造单个子集Set<Integer> sub = new HashSet<>();for (int j = 0; j < arr.length; j++) {if (((i >> j) & 1) == 1) {//若二进制第j+1位==1,则arr[j]加入子集sub.add(arr[j]);}}set.add(sub);}return set;}

【拓展】二进制解法还可以得出字典序逆序的子集排列。
若要求正序字典序的子集排列,则只需要再在main()对返回的list翻转一下就可以了。

/*** 二进制解法——逆序字典序——最优*      不含空集,且逆序字典序*      实现字典序逆序排列:1、对arr正序排序*                     2、从大数字》小数字遍历(2^n-1 —— 1)*                     3、从每位数的二进制高位到低位遍历,因为高位对应arr的靠后数字* @param arr* @return*/public static ArrayList<ArrayList<Integer>> subSet04(int[] arr) {Arrays.sort(arr);ArrayList<ArrayList<Integer>> set = new ArrayList<>();
//        1、从2^n-1 —— 1遍历每一位数,即每一种子集组合for (int i = (int)Math.pow(2,arr.length)-1; i > 0; i--) {//            遍历该数的二进制位,构造单个子集。ArrayList<Integer> sub = new ArrayList<>();for (int j = arr.length-1; j >= 0; j--) {if (((i >> j) & 1) == 1) {//若二进制第j+1位==1,则arr[j]加入子集sub.add(arr[j]);}}set.add(sub);}return set;}

三、算法性能比较:
二进制解法 > 迭代 > 递归
推荐:二进制解法。

【算法】求非空子集的三种思路相关推荐

  1. 求两个链表的第一个公共结点各种情况及三种思路分析

    转自:http://blog.csdn.net/ssopp24/article/details/72377184 1.寻找两个链表的第一个公共结//这道题可以有很多种思路, 我们按照, 有坏到好的顺序 ...

  2. c语言实现求最大公约数的三种方法

    一.最大公约数 最大公因数,也称最大公约数.最大公因子,指两个或多个整数共有约数中最大的一个.a,b的最大公约数记为(a,b),同样的,a,b,c的最大公约数记为(a,b,c),多个整数的最大公约数也 ...

  3. leetcode84- 柱状图中最大的矩形(三种思路:暴力,单调栈+哨兵(详解),分治)

    leetcode84- 柱状图中最大的矩形(三种思路:暴力,单调栈+哨兵(详解),分治) 介绍 题目 解题思路 解法一:暴力向两边搜索 解法二:单调栈 画图演示 宽度计算: 解法三:单调栈+哨兵 解法 ...

  4. 平台建设规划的三种思路——互联网平台建设

    互联网平台建设的第04篇文章,主要分享的是保险公司互联网平台建设规划的三种思路. 以下是数字化转型的分享线路图,您现在所在的位置为序号的分享:生态圈建设中,最关键的一部分,载体之平台建设. 以下是正文 ...

  5. mysql 分页查询web_JavaWeb分页显示内容之分页查询的三种思路(数据库分页查询)...

    JavaWeb分页显示内容之分页查询的三种思路(数据库分页查询)-1.jpg (40.23 KB, 下载次数: 0) 2018-8-18 13:34 上传 在开发过程中,经常做的一件事,也是最基本的事 ...

  6. Matlab求矩阵的逆(三种方法)

    Matlab求矩阵的逆(三种方法) 说明:若所求矩阵为非奇异矩阵(可逆矩阵),则可以精确求得其逆矩阵:若所求矩阵为奇异矩阵,则所求出的逆矩阵是近似的(不精确). 下面以矩阵A为例. inv()方法 A ...

  7. c语言数组最大可定义多少位_C语言求数组的最大值三种方法

    /* 黄哥Python培训 黄哥所写*/#include int maxValue(int* arr, int n);int maxRecursionValue(int* arr, int n);in ...

  8. matlab求pi值的三种方法

    https://www.icourse163.org/learn/CSU-1002475002?tid=1450231442#/learn/content?type=detail&id=121 ...

  9. MATLAB代码:全面ADMM算法代码,实现了三种ADMM迭代方式

    MATLAB代码:全面ADMM算法代码,实现了三种ADMM迭代方式 关键词:综合能源 分布式协同优化 交替方向乘子法 最优潮流 参考文档:<基于串行和并行ADMM算法的电_气能量流分布式协同优化 ...

最新文章

  1. hystrix 配置 不生效_12、Feign整合断路器Hystrix
  2. Xamarin基础命名空间Microsoft.SqlServer.Server
  3. 你还在问android横竖屏切换的生命周期?
  4. 在IE环境下用javascript触发ABAP event
  5. java实用教程——组件及事件处理——ActionEvent事件
  6. MinGW编译boost库
  7. 开源erp_大公司为何使用开源ERP
  8. 【目标检测】单阶段算法--YOLOv2详解
  9. C#,COM口,接收,发送数据
  10. web开发模式+三层架构与MVC
  11. 华硕UX433FN安装Win黑苹果双系统
  12. 【Unity3D入门教程】Unity3D播放音频和视频
  13. 用极致业务基础平台研发的族谱管理软件
  14. 【数仓】数据质量监控
  15. 【安全】被黑客要挟的一天,All your data is a backed up. You must pay 0.25BTC
  16. linux服务器怎么做快照,云服务器怎么创建快照
  17. JAVA——制作java程序说明书、解决DOS下中文编码问题 GBK
  18. (Java生产者消费者问题)http://blog.csdn.net/jhj735412/article/details/6931135
  19. Friends经典对白
  20. SAP S4 HANA 安装部署记事四:SAP HANA主机性能测试HWCCT

热门文章

  1. 手机控制电脑之手机端模拟鼠标滑动处理
  2. pytorch保存模型方法
  3. blender建模常用建模快捷键
  4. 飘飘微课计算机百度云,数学微课_百度云资源_盘多多如风搜_盘搜搜_哎哟喂啊...
  5. 因为这个原因,将谷歌浏览器更换到国产浏览器
  6. NIOS II 内核使用 之 代码保存FLASH(EPCSX芯片)
  7. Fater-Rcnn原理详解
  8. 曹翱,我永远爱你(FOR循环和WHILE循环讲解)
  9. CPGIS三十周年专访系列|陶闯主席
  10. iOS 苹果内购详细步骤