傻瓜方法求集合的所有子集问题(java版)
给定任意长度的一个集合,用一个数组表示,如{"a", "b","c"},求它的所有子集。结果是{ {a}, {b}, {c}, {a,b}, {a,c}, {b,c}, {a,b,c}}和一个空集。
下面讲的就是如何用一个原始的傻瓜方法(非算法)求它的所有子集。
首先我们知道是它的子集个数是2^length,如果长度是3,那子集就共有2的3次方=8个,包括空集。
求子集,我的做法是对任何一项做判断,有或者无,用1和0来对应表示。
那么像这种长度为3的,用二进制来表示就是000、001、010……
其实就是从0-2^3,用2进制表示出来就是所以的子集了。然后把0对应的子项给拿掉,譬如010对应的就是b,011对应的就是bc。只需要从0到2^3-1做一个循环,然后把0-7之间的数用二进制表示出来,再与原集合进行对比。把0对应位置的字符去掉,这样就得到了所有子集。
原理很简单,下面是代码
package huisu;
/**
* Created by wolf on 2016/3/22.
*/
public class GetSet {
private String[] origin = {"a", "b", "c"};
private String[] targetArray;
public static void main(String[] args) {
new GetSet().doJob();
}
private void doJob() {
//获取将要分解的字符串如果转为2进制最大是几
//如字符串是3位,就是2^3。从[0 0 0]到[1 1 1]
int maxLength = (int) Math.pow(2, origin.length);
targetArray = new String[maxLength];
for (int i = 0; i < targetArray.length; i++) {
//十进制转2进制
targetArray[i] = Integer.toBinaryString(i);
}
buling();
print();
}
/**
* 给空位补0,凑齐位数
*/
private void buling() {
for (int i = 0; i < targetArray.length; i++) {
//位数是完整的,不需要补0
if (targetArray[i].length() == origin.length) {
continue;
}
String temp = "";
//0,1,10,11,111
for (int j = 0; j < origin.length - targetArray[i].length(); j++) {
temp += "0";
}
targetArray[i] = temp + targetArray[i];
}
}
private void print(){
for (int i = 0; i < targetArray.length; i++) {
String s = targetArray[i];//如000,001,010
for (int j = 0; j < s.length(); j++) {
char item = s.charAt(j);
if (item == '1') {
System.out.print(origin[j]);
}
}
System.out.println();
}
}
}
在第23行是将10进制的0-7转成二进制,转之后如下图
这里就有个问题,那就是位数并不满,像0、10之类的,将来和原始数组做对应判断的时候有点小麻烦,所以我做了个处理,把位数补齐。保持和原始数组位数一样。
调用了buling(原谅我想不起来用什么英语来表示补零)方法,把位数不足的前面全补上0.然后就变成了000,001,010……这样就可以很方便的去判断了,只打印1所在的位数就行了。参考print方法。
总结:这种做法比较简单易懂。也能适应任意长度的求子集问题。根据这种做法,还能解决另外一个问题——01背包问题(有编号分别为a,b,c,d,e的五件物品,它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?)相信很容易能看出来,上面的方法求出来了所有子集,那么对于01背包问题,就是根据所有的子集,先砍掉所有超重的子集。然后去计算剩余的子集的价值,找到最大的就OK了。
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- Spring IOC源码最全分析
- 嵌入式linux之go语言开发(六)几行代码实现终端的远程日志诊断
- spring-mybatis 整合分析
- Spring 中循环依赖是如何解决?
- 走,HashMap,敢去爬山吗?
- Django+Vue开发生鲜电商平台之10.购物车、订单管理和支付功能
- 嵌入式linux之go语言开发(七)protobuf的使用
- 动手写简单的嵌入式操作系统一
- LeetCode 92 | 大公司常考的面试题,翻转链表当中指定部分
- 快速学习-Apollo从入门到精通
- dotnet 使用 SourceLink 将 NuGet 链接源代码到 GitHub 等仓库
- 嵌入式linux之go语言开发(八)存储模块的封装(一)
- QGIS制图中面积小的区域不显示注记
- linux 编译 c或cpp 文件为动态库 so 文件(最简单直观的模板)
- 满眼只有React和Vue,却对前端数据层几乎一无所知