(续昨天)老久没来博客园了,前几天和同事一起出去玩,一个女生给我出了个题,有四个数,分别是3,3,8,8,如何才能让他们经过+, -, *, / 四则运算最后结果得到24,我想了半天没想出来,汗!!!
不过这不是俺的作风啊,于是厚着脸皮吹牛说:“哥明天写程序给你算出来!”,经过一天的努力,终于写出来个支持n位数计算结果的算法,不过自认为效率很差,想看看大家的代码,然后改一改,欢迎一起来讨论啊!
由于本人水平有限,所以代码可读性可能很差,大家不要着急看代码,我先解释一下,我一共写了三个类,第一个类产生运算的结果队列,第二个类声明结果队列中节点的数据结构,里面有三项,第一项是Operand,操作数组成的队列,例如【8,3】&【5,3】&【8,8】;第二项是操作符号组成的队列,例如 1&0&0,其中1代表减号,0代表加号(看过程序就知道了);第三项是结果集,例如经过上面的运算 8-3+3+8,最后结果集中存的就只有16这个最后结果了 。
好了,本程序照理说应该可以算五位数六位数的加减乘除,但是现实中只有小于等于四位的可以成功,原因是四位数加减乘除产生的结果有C42×C32×6×6×6个结果,如果出去除数为零的情况,resultlist这个队列中要有三千多个值,要是五位可能几十万个,六位就有三千多万个,晕!堆栈溢出了!那位高手可以指点一下我改进改进算法,呵呵~
ResultList类
import java.math.BigDecimal;
import java.util.ArrayList;
public class ResultList {
public void OP(ResultNode node) {
ArrayList Data = node.ResultSet;
if (Data.size() > 1) {
// 对给定的一组数中选出两个进行组合,返回组合的索引值
ArrayList OperandIndextList = Cn2(Data,Data.size());
for (int i = 0; i < OperandIndextList.size(); i++) {
int[] OperandIndext = (int[])OperandIndextList.get(i);
// 由于Cn2函数返回的是索引而不是数值,所以在此转换成数值OperandData,即得到两个操作数
BigDecimal[] OperandData = new BigDecimal[2];
OperandData[0] = (BigDecimal)Data.get(OperandIndext[0]);
OperandData[1] = (BigDecimal)Data.get(OperandIndext[1]);
// 返回两个操作数的结果集
ArrayList OpResult = getResult(OperandData);
// 遍历结果集里的结果(共6个,如果除数为零则为五个)
for (int j = 0; j < OpResult.size(); j++) {
// 在此产生一组新的数,该组数值是除掉Data中的两个操作数,加入本次的运算结果产生的,备下次递归使用
ArrayList ResultData = (ArrayList)Data.clone();
ResultData.remove(OperandIndext[0]);
ResultData.remove(OperandIndext[1]-1);
ResultData.add(OpResult.get(j));
// 生成resultList的节点实例
ResultNode resultNode = new ResultNode();
// 该节点要保留递归运算中上次的操作数和操作符号,所以操组数和符号用队列存储
resultNode.Operand = (ArrayList)node.Operand.clone();
resultNode.Operater = (ArrayList)node.Operater.clone();
// 添加本次的两个操作数
resultNode.Operand.add(OperandData);
// 添加本次运算的操作符号运算
resultNode.Operater.add(new BigDecimal(j));
// 添加本次新产生的结果集
resultNode.ResultSet = ResultData;
resultList.add(resultNode);
}
}
// 循环递归开始
for(int i = 0; i < resultList.size(); i++) {
// 所谓的newnode是上次产生的节点,作为本次的输入参数
ResultNode newnode = (ResultNode)resultList.get(i);
/* 如果结果集中的结果大于一个,那么不用说,接着循环,递归,算结果吧,
* 如果等于一个那么跳出循环,它就是最终结果。
* */
if (newnode.ResultSet.size() > 1) {
resultList.remove(i);
} else { break; }
// 递归
OP(newnode);
}
}
}
/*该方法产生两个操作数经过计算可能产生的所有数值,加法和乘法不必说了,
* 注意的是减法和除法如果交换连个操作数可能产生不同的结果,所以有六种
* 可能。
* */
private ArrayList getResult(BigDecimal[] Data) {
BigDecimal result;
ArrayList resultList = new ArrayList();
for (int i=0; i<6; i++ ) {
result = new BigDecimal(0);
switch(i) {
case 0:
result = Data[0].add(Data[1]);
resultList.add(result);
break;
case 1:
result = Data[0].subtract(Data[1]);
resultList.add(result);
break;
case 2:
result = Data[1].subtract(Data[0]);
resultList.add(result);
break;
case 3:
result = Data[0].multiply(Data[1]);
resultList.add(result);
break;
case 4:
if (Data[1].compareTo(new BigDecimal("0")) != 0) {
result = Data[0].divide(Data[1], 10, BigDecimal.ROUND_HALF_UP);
resultList.add(result);
}
break;
case 5:
if (Data[0].compareTo(new BigDecimal("0")) != 0) {
result = Data[1].divide(Data[0], 10, BigDecimal.ROUND_HALF_UP);
resultList.add(result);
}
break;
}
}
return resultList;
}
/*该方法从所给的所有数中选中两个作为操作数,返回值是所有可能的索引
* 例如: 输入3 2 8,返回的组合是 12,13,23所组成的队列,
* 而不是 32,28,38所组成的队列
* */
private ArrayList Cn2(ArrayList Data, int n) {
ArrayList resultList = new ArrayList();
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
int[] result = new int[2];
result[0] = i;
result[1] = j;
resultList.add(result);
}
}
return resultList;
}
public ResultList() {
resultList = new ArrayList();
}
public ArrayList getResultList() {
return resultList;
}
private ArrayList resultList;
}
import java.math.BigDecimal;
import java.util.ArrayList;
public class ResultList {
public void OP(ResultNode node) {
ArrayList Data = node.ResultSet;
if (Data.size() > 1) {
// 对给定的一组数中选出两个进行组合,返回组合的索引值
ArrayList OperandIndextList = Cn2(Data,Data.size());
for (int i = 0; i < OperandIndextList.size(); i++) {
int[] OperandIndext = (int[])OperandIndextList.get(i);
// 由于Cn2函数返回的是索引而不是数值,所以在此转换成数值OperandData,即得到两个操作数
BigDecimal[] OperandData = new BigDecimal[2];
OperandData[0] = (BigDecimal)Data.get(OperandIndext[0]);
OperandData[1] = (BigDecimal)Data.get(OperandIndext[1]);
// 返回两个操作数的结果集
ArrayList OpResult = getResult(OperandData);
// 遍历结果集里的结果(共6个,如果除数为零则为五个)
for (int j = 0; j < OpResult.size(); j++) {
// 在此产生一组新的数,该组数值是除掉Data中的两个操作数,加入本次的运算结果产生的,备下次递归使用
ArrayList ResultData = (ArrayList)Data.clone();
ResultData.remove(OperandIndext[0]);
ResultData.remove(OperandIndext[1]-1);
ResultData.add(OpResult.get(j));
// 生成resultList的节点实例
ResultNode resultNode = new ResultNode();
// 该节点要保留递归运算中上次的操作数和操作符号,所以操组数和符号用队列存储
resultNode.Operand = (ArrayList)node.Operand.clone();
resultNode.Operater = (ArrayList)node.Operater.clone();
// 添加本次的两个操作数
resultNode.Operand.add(OperandData);
// 添加本次运算的操作符号运算
resultNode.Operater.add(new BigDecimal(j));
// 添加本次新产生的结果集
resultNode.ResultSet = ResultData;
resultList.add(resultNode);
}
}
// 循环递归开始
for(int i = 0; i < resultList.size(); i++) {
// 所谓的newnode是上次产生的节点,作为本次的输入参数
ResultNode newnode = (ResultNode)resultList.get(i);
/* 如果结果集中的结果大于一个,那么不用说,接着循环,递归,算结果吧,
* 如果等于一个那么跳出循环,它就是最终结果。
* */
if (newnode.ResultSet.size() > 1) {
resultList.remove(i);
} else { break; }
// 递归
OP(newnode);
}
}
}
/*该方法产生两个操作数经过计算可能产生的所有数值,加法和乘法不必说了,
* 注意的是减法和除法如果交换连个操作数可能产生不同的结果,所以有六种
* 可能。
* */
private ArrayList getResult(BigDecimal[] Data) {
BigDecimal result;
ArrayList resultList = new ArrayList();
for (int i=0; i<6; i++ ) {
result = new BigDecimal(0);
switch(i) {
case 0:
result = Data[0].add(Data[1]);
resultList.add(result);
break;
case 1:
result = Data[0].subtract(Data[1]);
resultList.add(result);
break;
case 2:
result = Data[1].subtract(Data[0]);
resultList.add(result);
break;
case 3:
result = Data[0].multiply(Data[1]);
resultList.add(result);
break;
case 4:
if (Data[1].compareTo(new BigDecimal("0")) != 0) {
result = Data[0].divide(Data[1], 10, BigDecimal.ROUND_HALF_UP);
resultList.add(result);
}
break;
case 5:
if (Data[0].compareTo(new BigDecimal("0")) != 0) {
result = Data[1].divide(Data[0], 10, BigDecimal.ROUND_HALF_UP);
resultList.add(result);
}
break;
}
}
return resultList;
}
/*该方法从所给的所有数中选中两个作为操作数,返回值是所有可能的索引
* 例如: 输入3 2 8,返回的组合是 12,13,23所组成的队列,
* 而不是 32,28,38所组成的队列
* */
private ArrayList Cn2(ArrayList Data, int n) {
ArrayList resultList = new ArrayList();
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
int[] result = new int[2];
result[0] = i;
result[1] = j;
resultList.add(result);
}
}
return resultList;
}
public ResultList() {
resultList = new ArrayList();
}
public ArrayList getResultList() {
return resultList;
}
private ArrayList resultList;
}
ResultNode 类
import java.util.ArrayList;
public class ResultNode {
public ArrayList Operand;
public ArrayList Operater;
public ArrayList ResultSet;
public ResultNode() {
Operand = new ArrayList();
Operater = new ArrayList();
ResultSet = new ArrayList();
}
}
import java.util.ArrayList;
public class ResultNode {
public ArrayList Operand;
public ArrayList Operater;
public ArrayList ResultSet;
public ResultNode() {
Operand = new ArrayList();
Operater = new ArrayList();
ResultSet = new ArrayList();
}
}
测试类
import java.math.BigDecimal;
public class TestResutList {
public static void main(String[] args) {
// 输入要计算的数值
ResultNode beginNode = new ResultNode();
beginNode.ResultSet.add(new BigDecimal("3"));
beginNode.ResultSet.add(new BigDecimal("3"));
beginNode.ResultSet.add(new BigDecimal("8"));
beginNode.ResultSet.add(new BigDecimal("8"));
// 计算的目标值
BigDecimal goal = new BigDecimal("24");
// 计算得出结果队列
ResultList resultlist = new ResultList();
resultlist.OP(beginNode);
// 遍历结果队列,如果找出满足条件的一个节点,则打印节点信息,然后跳出循环
for (int i =0 ; i< resultlist.getResultList().size(); i++) {
// 节点
ResultNode node = (ResultNode)resultlist.getResultList().get(i);
// 节点存储的结果
BigDecimal result = (BigDecimal)node.ResultSet.get(0);
// 转换精度
BigDecimal rscl = result.setScale(5,BigDecimal.ROUND_HALF_UP);
// 如果满足条件,打印结果
if ( rscl.compareTo(goal)==0) {
for (int j = 0; j < node.Operand.size(); j ++) {
BigDecimal[] Operand = (BigDecimal[])node.Operand.get(j);
switch(((BigDecimal)node.Operater.get(j)).intValue()) {
case 0:
System.out.print("Operand: "+Operand[0]);
System.out.print(" ");
System.out.print(Operand[1]);
System.out.print(" ");
System.out.println("Operater: "+"+");
break;
case 1:
System.out.print("Operand: "+Operand[0]);
System.out.print(" ");
System.out.print(Operand[1]);
System.out.print(" ");
System.out.println("Operater: "+"-");
break;
case 2:
System.out.print("Operand: "+Operand[1]);
System.out.print(" ");
System.out.print(Operand[0]);
System.out.print(" ");
System.out.println("Operater: "+"-");
break;
case 3:
System.out.print("Operand: "+Operand[0]);
System.out.print(" ");
System.out.print(Operand[1]);
System.out.print(" ");
System.out.println("Operater: "+"*");
break;
case 4:
System.out.print("Operand: "+Operand[0]);
System.out.print(" ");
System.out.print(Operand[1]);
System.out.print(" ");
System.out.println("Operater: "+"/");
break;
case 5:
System.out.print("Operand: "+Operand[1]);
System.out.print(" ");
System.out.print(Operand[0]);
System.out.print(" ");
System.out.println("Operater: "+"/");
break;
}
}
break;
}
}
}
}
import java.math.BigDecimal;
public class TestResutList {
public static void main(String[] args) {
// 输入要计算的数值
ResultNode beginNode = new ResultNode();
beginNode.ResultSet.add(new BigDecimal("3"));
beginNode.ResultSet.add(new BigDecimal("3"));
beginNode.ResultSet.add(new BigDecimal("8"));
beginNode.ResultSet.add(new BigDecimal("8"));
// 计算的目标值
BigDecimal goal = new BigDecimal("24");
// 计算得出结果队列
ResultList resultlist = new ResultList();
resultlist.OP(beginNode);
// 遍历结果队列,如果找出满足条件的一个节点,则打印节点信息,然后跳出循环
for (int i =0 ; i< resultlist.getResultList().size(); i++) {
// 节点
ResultNode node = (ResultNode)resultlist.getResultList().get(i);
// 节点存储的结果
BigDecimal result = (BigDecimal)node.ResultSet.get(0);
// 转换精度
BigDecimal rscl = result.setScale(5,BigDecimal.ROUND_HALF_UP);
// 如果满足条件,打印结果
if ( rscl.compareTo(goal)==0) {
for (int j = 0; j < node.Operand.size(); j ++) {
BigDecimal[] Operand = (BigDecimal[])node.Operand.get(j);
switch(((BigDecimal)node.Operater.get(j)).intValue()) {
case 0:
System.out.print("Operand: "+Operand[0]);
System.out.print(" ");
System.out.print(Operand[1]);
System.out.print(" ");
System.out.println("Operater: "+"+");
break;
case 1:
System.out.print("Operand: "+Operand[0]);
System.out.print(" ");
System.out.print(Operand[1]);
System.out.print(" ");
System.out.println("Operater: "+"-");
break;
case 2:
System.out.print("Operand: "+Operand[1]);
System.out.print(" ");
System.out.print(Operand[0]);
System.out.print(" ");
System.out.println("Operater: "+"-");
break;
case 3:
System.out.print("Operand: "+Operand[0]);
System.out.print(" ");
System.out.print(Operand[1]);
System.out.print(" ");
System.out.println("Operater: "+"*");
break;
case 4:
System.out.print("Operand: "+Operand[0]);
System.out.print(" ");
System.out.print(Operand[1]);
System.out.print(" ");
System.out.println("Operater: "+"/");
break;
case 5:
System.out.print("Operand: "+Operand[1]);
System.out.print(" ");
System.out.print(Operand[0]);
System.out.print(" ");
System.out.println("Operater: "+"/");
break;
}
}
break;
}
}
}
}