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。
上代码
执行的结果:
相加等于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. 穷举法暴力查找,效率差。
我们把这个较大的数称作“和”,用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穷举法递归实现:查找一个数等于一组数中哪些数相加的和
- 查找一个数等于一组数中某些数相加的和
- JAVA函数实现任意给定一组数, 找出任意数相加等于某数或者在一个范围
- 在一组序列中查找两个元素的和等于给定的值(快排+两端扫描实现)
- 一个递归和非递归实现二分查找的代码
- 递归实现十个数相加等于100
- java实现输入一个正整数n,输出全部连续正整数相加后等于n的所有序列。
- 写一个功能函数实现从数组中找出两个值相加等于某一个值,要求时间复杂度为 n;
- 编写查找一个单链表特定元素的程序。分别使用递归和非递归方法实现,并比较它们的运行时间。
- 数据结构 —— 二叉树 前序、中序、后序、层次遍历及非递归实现 查找、统计个数、比较、求深度的递归实现
- 二叉查找树之——非递归实现
- 算法题/用递归实现一个字符串的全排列
- 无限极分类中递归查找一个树结构
- 编程实现: 一组数据中只有一个数字出现了一次。其他所有数字都是成对出现的。 请找出这个数字。(使用位运算)
- 编写一个函数实现n^k,使用递归实现
- 编写一个函数实现n^k,使用递归实现
- 二分查找的递归实现
- 一个实现长整型数相加减的小程序
- c++实现二分查找 递归和非递归
- 二分查找的递归和非递归实现