您的位置:首页 > 编程语言 > Java开发

JAVA穷举法递归实现:查找一个数等于一组数中哪些数相加的和

2013-08-30 15:38 288 查看
前两天,同事问我怎么处理这个问题:他手里有一个比较大的数,还有一堆乱七八糟的数,怎样找出那些数相加等于这个比较大的数。我想了想感觉这是个比较恶心的算法,在网上找了有很多例子,都觉得不太合适。

我们把这个较大的数称作“和”,用sum表示,计算查找的时候我们可能会遇到一些问题:

1. sum没有规则,可能非常大,还可能带着小数点。所以不能用普通的int类型来计算。

2. 数组中可能存在多个集合符合条件,且元素个数不同,比如(1+2+3+4)=10,(4+6)=10。还有可能组中存在重复数据,比如(1+1+2)=4,(2+2)=4。这样用循环语句写就非常麻烦,应该用递归方法。

3. 会不会有的元素就等于“和”本身呢?

我想了一下午,觉得可以用穷举法暴力查找实现:

首先,我们拿到了一个乱七八糟的数组,我们先给他排个序,升序排序,从小到大。

然后,为了增加循环递归的效率,先把相加结果肯定不等于sum的数去掉。数组已经是按大小个排序了,就用最大的数加最小的数,如果相加大于sum,那这个最大数在这个数组里跟谁加都不会等于sum,果断踢走。max+min>sum,则删除max。

最后,数组都排完序了,“太大个”的都踢走了。剩下的就是我们要循环查找的数了。

double a={a0,a1,a2…..an},如果a
+a[n-1]>sum,跳过a[n-1],判断a
+a[n-2]和sum的关系;如果a
+a[n-2]<sum,则再查找(a
+a[n-2])+a[n-3]与sum的关系,循环调用此逻辑,可获我们要查找的结果a
+a[x]+….+a[y]=sum或者无任何元素相加等于sum。

 

上代码

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class CreateTest {
private static List<Integer> findNumIndex;// 存储符合条件的数组元素下表
private static boolean findon;// 是否可以从数组中找到相加等于“和”的元素
private static boolean someoneEqualSum;// 数组中是否有某个元素等于“和”本身
private static double[] a;// 数组
private static double sum;// “和”

public CreateTest(double[] a, double sum) {
this.a = a;
this.sum = sum;
findon = false;
findNumIndex = new ArrayList<Integer>();
someoneEqualSum = false;
}

public void start() {
a = maopao(a);// 首先冒泡排序
List<Double> list = new LinkedList<Double>();
for (int i = 0; i < a.length; i++) {// 把double数组付给list
list.add(a[i]);
}
boolean flag = true;
do {
double mix = list.get(0);// 当前最小值
double max = list.get(list.size() - 1);// 当前最大值
if (max == sum) {// 找到等于“和”的元素,打个标记
someoneEqualSum = true;
}
if (mix + max > sum && flag) {// 删除没用的最大值
list.remove(list.size() - 1);
} else {
flag = false;
}
} while (flag);
startMath(list, sum);
if (!findon) {
System.out.println("未找到符合条件的数组");
}
}

public double[] maopao(double[] a) {
for (int i = 0; i < a.length - 1; i++) {
for (int k = 0; k < a.length - 1 - i; k++) {
if (a[k] > a[k + 1]) {
double b = a[k];
a[k] = a[k + 1];
a[k + 1] = b;
}
}
}
return a;
}

public void startMath(List<Double> list, double sum) {
if (someoneEqualSum) {// 先输出等于“和”本身的数
System.out.println("相加等于" + sum + "的数组为:");
System.out.println(sum);
System.out.println("-----------------------");
}
for (int i = 0; i <= list.size() - 2; i++) {
findNumIndex.clear();
findNumIndex.add(list.size() - 1 - i);// 记录第一个元素坐标
double indexNum = list.get(list.size() - 1 - i);// 从最大的元素开始,依次往前推
action(list, indexNum, list.size() - 1 - i, sum);
}
}

/**
* 递归方法
*
* @param list
*            被查询的数组
* @param indexsum
*            当前元素相加的和
* @param index
*            下一个元素位置
* @param sum
*            要匹配的和
*/
public void action(List<Double> list, double indexsum, int index, double sum) {
if (index == 0)
return;
if (indexsum + list.get(index - 1) > sum) {// 元素【index-1】太大了,跳到下一个元素继续遍历
action(list, indexsum, index - 1, sum);
} else if (indexsum + list.get(index - 1) < sum) {// 元素【index-1】可能符合条件,继续往下找
findNumIndex.add(index - 1);// 记录此元素坐标
indexsum = indexsum + list.get(index - 1);// 更新元素的和
action(list, indexsum, index - 1, sum);
} else if (indexsum + list.get(index - 1) == sum) {
findNumIndex.add(index - 1);
findon = true;// 告诉系统找到了
System.out.println("相加等于" + sum + "的数组为:");
for (int a : findNumIndex) {
System.out.println(list.get(a));
}
System.out.println("-----------------------");
return;
}
}

public static void main(String[] args) {
double[] a = { 1, 8.3, 43, 22, 12, 7, 65, 100, 86, 97, 14, 53, 523,
555, 265, 74, 2, 556, 76, 98, 34, 78, 33, 50, 22 };
double sum = 100;
CreateTest s = new CreateTest(a, sum);
s.start();
}
}


 

执行的结果:

相加等于100.0的数组为:

100.0

-----------------------

相加等于100.0的数组为:

98.0

2.0

-----------------------

相加等于100.0的数组为:

97.0

2.0

1.0

-----------------------

相加等于100.0的数组为:

86.0

14.0

-----------------------

相加等于100.0的数组为:

78.0

22.0

-----------------------

相加等于100.0的数组为:

76.0

22.0

2.0

-----------------------

相加等于100.0的数组为:

65.0

34.0

1.0

-----------------------

相加等于100.0的数组为:

50.0

43.0

7.0

-----------------------

相加等于100.0的数组为:

43.0

34.0

22.0

1.0

-----------------------

代码优点:

1. 可输出多组符合条件的集合

2. 可以输出等于sum本身的元素

3. 循环递归调用

4. 支持小数点

代码缺点:

1. 程序有一个bug:如果sum=100,数组={98,2,1,1},输出的结果只有98+2=100。结果98+1+1=100被忽略了。

2. 穷举法暴力查找,效率差。

 

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  JAVA 递归