根据数组数据,得到和一定的所有子集

给定一个数字数组,设定一个目标值, 然后以这个数组为数据源,要求给出所有的子集,这些子集中数据的和要等于设定的目标值。例如: 数字数组: [1,2,3,4,5,6] 目标值为 7 那么,所有和为7的子集有[1,2,4] [3,4]......

import java.util.Stack;

/**
* 给定一个数字数组,设定一个目标值, 然后以这个数组为数据源,要求给出所有的子集,这些子集中数据的和要等于设定的目标值。
*
* 例如: 数字数组: [1,2,3,4,5,6] 目标值为 7 那么,所有和为7的子集有[1,2,4] [3,4]......
*
* 本例子中采用了Stack来实现, 提供了两个public方法:
* 1. 用于输出所有符合条件的结果
* 2. 可以设定子集中的元素的个数范围,从而输出符合此条件的子集
*
* @author Eric
* @version 1.0
*
*/

public class PopulateSubsetByStack {

private Stack<Integer> stack = new Stack<Integer>();

// 用于字符串的相加
private StringBuilder sb = new StringBuilder();

public void populateSubset(int[] values, int begin, int end,
int sumInStack, int expectedSum) {

/*
* 判断Stack中的数据和是否等于目标值,如果是则输出当前Stack中的数据
*/
if (sumInStack == expectedSum) {
print(stack, expectedSum);
}

for (int currentIndex = begin; currentIndex < end; currentIndex++) {
/*
* 如果当前Stack中的和加上当前index的数据小于等于目标值, 那么将当前的index的数据添加到Stack中去,
* 同时,将当前Stack中所有数据的和加上新添加到Stack中的数值
*/
if (sumInStack + values[currentIndex] <= expectedSum) {
stack.push(values[currentIndex]);
sumInStack += values[currentIndex];
// 当前index加上1,递归调用本身
populateSubset(values, currentIndex + 1, end, sumInStack,
expectedSum);

sumInStack -= stack.pop();
}

}
}

/**
* 如果想控制满足条件的集合中元素的个数范围,也可以最大和最小值
*/
public void populateSubset(int[] values, int begin, int end,
int sumInStack, int expectedSum, int minNum, int maxNum) {

/*
* 判断Stack中的数据和是否等于目标值,如果是则输出当前Stack中的数据
*/
if (sumInStack == expectedSum) {

/*
* 只有当子集中元素个数在期望的范围内[minNum, maxNum],才打印出结果。
*/
if (stack.size() >= minNum && stack.size() <= maxNum) {
print(stack, expectedSum);
}
}

for (int currentIndex = begin; currentIndex < end; currentIndex++) {
/*
* 如果当前Stack中的和加上当前index的数据小于等于目标值, 那么将当前的index的数据添加到Stack中去,
* 同时,将当前Stack中所有数据的和加上新添加到Stack中的数值
*/
if (sumInStack + values[currentIndex] <= expectedSum) {
stack.push(values[currentIndex]);
sumInStack += values[currentIndex];
// 当前index加上1,递归调用本身
populateSubset(values, currentIndex + 1, end, sumInStack,
expectedSum, minNum, maxNum);

sumInStack -= stack.pop();
}

}
}

/**
* 打印符合条件的子集数据 如:15 = 1+2+4+6+2
*
* @param stack
* @param expectedSum
*/
private void print(Stack<Integer> stack, int expectedSum) {
sb.setLength(0);
sb.append(expectedSum + " = ");
for (int element : stack) {
sb.append(element + "+");
}
System.out.println(sb.deleteCharAt(sb.length() - 1).toString());
}

public static void main(String[] args) {

// 指定数据集
int[] sourceData = { 1, 2, 3, 4, 5, 6, 2, 7, 8, 9, 10, 11, 13, 14, 15 };

PopulateSubsetByStack example = new PopulateSubsetByStack();

/*
* 计算并打印出和为15的所有子集
*/
System.out.println("计算并打印出和为15的所有子集");
example.populateSubset(sourceData, 0, sourceData.length, 0, 15);

/*
* 计算并打印出和为18的所有子集
*/
System.out.println("计算并打印出和为18的所有子集");
example.populateSubset(sourceData, 0, sourceData.length, 0, 18);

/*
* 计算和为15的所有子集,并且子集中的元素个数要至少3个至多5个。
*/
System.out.println("计算和为15的所有子集,并且子集中的元素个数要至少3个至多5个");
example.populateSubset(sourceData, 0, sourceData.length, 0, 15, 3, 5);
}
}


结果输出如下:
计算并打印出和为15的所有子集
15 = 1+2+3+4+5
15 = 1+2+3+2+7
15 = 1+2+3+9
15 = 1+2+4+6+2
15 = 1+2+4+8
15 = 1+2+5+7
15 = 1+2+2+10
15 = 1+3+4+5+2
15 = 1+3+4+7
15 = 1+3+5+6
15 = 1+3+2+9
15 = 1+3+11
15 = 1+4+2+8
15 = 1+4+10
15 = 1+5+2+7
15 = 1+5+9
15 = 1+6+8
15 = 1+14
15 = 2+3+4+6
15 = 2+3+2+8
15 = 2+3+10
15 = 2+4+2+7
15 = 2+4+9
15 = 2+5+6+2
15 = 2+5+8
15 = 2+6+7
15 = 2+2+11
15 = 2+13
15 = 3+4+6+2
15 = 3+4+8
15 = 3+5+7
15 = 3+2+10
15 = 4+5+6
15 = 4+2+9
15 = 4+11
15 = 5+2+8
15 = 5+10
15 = 6+2+7
15 = 6+9
15 = 2+13
15 = 7+8
15 = 15
计算并打印出和为18的所有子集
18 = 1+2+3+4+6+2
18 = 1+2+3+4+8
18 = 1+2+3+5+7
18 = 1+2+3+2+10
18 = 1+2+4+5+6
18 = 1+2+4+2+9
18 = 1+2+4+11
18 = 1+2+5+2+8
18 = 1+2+5+10
18 = 1+2+6+2+7
18 = 1+2+6+9
18 = 1+2+2+13
18 = 1+2+7+8
18 = 1+2+15
18 = 1+3+4+2+8
18 = 1+3+4+10
18 = 1+3+5+2+7
18 = 1+3+5+9
18 = 1+3+6+8
18 = 1+3+14
18 = 1+4+5+6+2
18 = 1+4+5+8
18 = 1+4+6+7
18 = 1+4+2+11
18 = 1+4+13
18 = 1+5+2+10
18 = 1+6+2+9
18 = 1+6+11
18 = 1+2+7+8
18 = 1+2+15
18 = 1+7+10
18 = 1+8+9
18 = 2+3+4+2+7
18 = 2+3+4+9
18 = 2+3+5+6+2
18 = 2+3+5+8
18 = 2+3+6+7
18 = 2+3+2+11
18 = 2+3+13
18 = 2+4+5+7
18 = 2+4+2+10
18 = 2+5+2+9
18 = 2+5+11
18 = 2+6+2+8
18 = 2+6+10
18 = 2+2+14
18 = 2+7+9
18 = 3+4+5+6
18 = 3+4+2+9
18 = 3+4+11
18 = 3+5+2+8
18 = 3+5+10
18 = 3+6+2+7
18 = 3+6+9
18 = 3+2+13
18 = 3+7+8
18 = 3+15
18 = 4+5+2+7
18 = 4+5+9
18 = 4+6+8
18 = 4+14
18 = 5+6+7
18 = 5+2+11
18 = 5+13
18 = 6+2+10
18 = 2+7+9
18 = 7+11
18 = 8+10
计算和为15的所有子集,并且子集中的元素个数要至少3个至多5个
15 = 1+2+3+4+5
15 = 1+2+3+2+7
15 = 1+2+3+9
15 = 1+2+4+6+2
15 = 1+2+4+8
15 = 1+2+5+7
15 = 1+2+2+10
15 = 1+3+4+5+2
15 = 1+3+4+7
15 = 1+3+5+6
15 = 1+3+2+9
15 = 1+3+11
15 = 1+4+2+8
15 = 1+4+10
15 = 1+5+2+7
15 = 1+5+9
15 = 1+6+8
15 = 2+3+4+6
15 = 2+3+2+8
15 = 2+3+10
15 = 2+4+2+7
15 = 2+4+9
15 = 2+5+6+2
15 = 2+5+8
15 = 2+6+7
15 = 2+2+11
15 = 3+4+6+2
15 = 3+4+8
15 = 3+5+7
15 = 3+2+10
15 = 4+5+6
15 = 4+2+9
15 = 5+2+8
15 = 6+2+7
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值