【算法】求非空子集的三种思路
一、题目:
简化:编写一个方法,返回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;}
三、算法性能比较:
二进制解法 > 迭代 > 递归
推荐:二进制解法。
【算法】求非空子集的三种思路相关推荐
- 求两个链表的第一个公共结点各种情况及三种思路分析
转自:http://blog.csdn.net/ssopp24/article/details/72377184 1.寻找两个链表的第一个公共结//这道题可以有很多种思路, 我们按照, 有坏到好的顺序 ...
- c语言实现求最大公约数的三种方法
一.最大公约数 最大公因数,也称最大公约数.最大公因子,指两个或多个整数共有约数中最大的一个.a,b的最大公约数记为(a,b),同样的,a,b,c的最大公约数记为(a,b,c),多个整数的最大公约数也 ...
- leetcode84- 柱状图中最大的矩形(三种思路:暴力,单调栈+哨兵(详解),分治)
leetcode84- 柱状图中最大的矩形(三种思路:暴力,单调栈+哨兵(详解),分治) 介绍 题目 解题思路 解法一:暴力向两边搜索 解法二:单调栈 画图演示 宽度计算: 解法三:单调栈+哨兵 解法 ...
- 平台建设规划的三种思路——互联网平台建设
互联网平台建设的第04篇文章,主要分享的是保险公司互联网平台建设规划的三种思路. 以下是数字化转型的分享线路图,您现在所在的位置为序号的分享:生态圈建设中,最关键的一部分,载体之平台建设. 以下是正文 ...
- mysql 分页查询web_JavaWeb分页显示内容之分页查询的三种思路(数据库分页查询)...
JavaWeb分页显示内容之分页查询的三种思路(数据库分页查询)-1.jpg (40.23 KB, 下载次数: 0) 2018-8-18 13:34 上传 在开发过程中,经常做的一件事,也是最基本的事 ...
- Matlab求矩阵的逆(三种方法)
Matlab求矩阵的逆(三种方法) 说明:若所求矩阵为非奇异矩阵(可逆矩阵),则可以精确求得其逆矩阵:若所求矩阵为奇异矩阵,则所求出的逆矩阵是近似的(不精确). 下面以矩阵A为例. inv()方法 A ...
- c语言数组最大可定义多少位_C语言求数组的最大值三种方法
/* 黄哥Python培训 黄哥所写*/#include int maxValue(int* arr, int n);int maxRecursionValue(int* arr, int n);in ...
- matlab求pi值的三种方法
https://www.icourse163.org/learn/CSU-1002475002?tid=1450231442#/learn/content?type=detail&id=121 ...
- MATLAB代码:全面ADMM算法代码,实现了三种ADMM迭代方式
MATLAB代码:全面ADMM算法代码,实现了三种ADMM迭代方式 关键词:综合能源 分布式协同优化 交替方向乘子法 最优潮流 参考文档:<基于串行和并行ADMM算法的电_气能量流分布式协同优化 ...
最新文章
- hystrix 配置 不生效_12、Feign整合断路器Hystrix
- Xamarin基础命名空间Microsoft.SqlServer.Server
- 你还在问android横竖屏切换的生命周期?
- 在IE环境下用javascript触发ABAP event
- java实用教程——组件及事件处理——ActionEvent事件
- MinGW编译boost库
- 开源erp_大公司为何使用开源ERP
- 【目标检测】单阶段算法--YOLOv2详解
- C#,COM口,接收,发送数据
- web开发模式+三层架构与MVC
- 华硕UX433FN安装Win黑苹果双系统
- 【Unity3D入门教程】Unity3D播放音频和视频
- 用极致业务基础平台研发的族谱管理软件
- 【数仓】数据质量监控
- 【安全】被黑客要挟的一天,All your data is a backed up. You must pay 0.25BTC
- linux服务器怎么做快照,云服务器怎么创建快照
- JAVA——制作java程序说明书、解决DOS下中文编码问题 GBK
- (Java生产者消费者问题)http://blog.csdn.net/jhj735412/article/details/6931135
- Friends经典对白
- SAP S4 HANA 安装部署记事四:SAP HANA主机性能测试HWCCT