今天看到一个帖子说程序员面试考24点算法,想为什么不用程序来实现呢。在网上没有找到非常完美的算法,包括那个24点计算器,给出的结果重复的也较多。所以自己写了一个。在这儿贴出来给大家分享一下。附源码。
问题
给出4个1~10之间的数字,使用加、减、乘、除和括号列出一个计算结果为24的算式。比如: 3、3、8、8 可以写成 8/(3-8/3)。但不是每一个都像这个例子只有一个结果,需要列出所有可能的算式。
思路
四个数字可以排列。都不同的情况下可能有24中。
每两个数字之间可以有一个双目运算符。一共可以添加三个运算符,并且只能三个。
可以通过添加括号的方式改变运算计算顺序,不考虑优先级,一共应该有5种添加括号的方式。
算法
对给出的4个数字进行排列组合,需要去掉相同数值重复的问题,如果各个数字都不相同有24种排列。参见排列组合算法。
对每一个排列插入3个运算符,4个运算符3个位置所以有3^4=64个组合。
逆波兰式用运行符位置来代替括号的组合方式,用枚举法,一共5种。
a b + c + d + => (((a+b)+c)+d)
a b + c d + + => ((a+b)+(c+d))
a b c + d + + => (a+((b+c)+d))
a b c + + d + => ((a+(b+c))+d)
a b c d + + + => (a+(b+(c+d)))
用分数来计算算式的结果,如果结果是24就获得一个符合要求的算式。
将符合条件逆波兰式转换成括号方式的四则运算表达式,并输出。不同的逆波兰式转换为四则运算可能重复(如果每一步加括号是不重复的)。
结果
源码
GitHub 地址 https://github.com/codefan/codeForFun
public class Calculation24 {
private static Map> foundReslutions = new HashMap<>(50);
/**
* 非递归的排列组合
* @param listSouce 可 排序的 列表
* @param comparable 比较函数
* @param consumer 消费排序结果
* @param 泛型
*/
public static void permutation(List listSouce ,
Comparator super T> comparable,
Consumer> consumer){
if(listSouce.size()<2){
consumer.accept(listSouce);
return;
}
listSouce.sort(comparable);
int len = listSouce.size();
List comPos = new ArrayList<>(len);
List usedItem = new ArrayList<>(len);
List comRes = new ArrayList<>(len);
for(int i=0;i
comPos.add(-1);
usedItem.add(false);
comRes.add(null);
}