您的位置:首页 > Web前端 > JavaScript

算法性能比较(三)——24点算法优化(怎么从low到爆变成唉哟不错哦)

2018-03-12 11:27 381 查看
原题简单描述如下:

给定4个参数(参数为整数,范围为1-100),以最快的速度找出对应的24点算法(无需找到全部算法,只要找到任意一个可行算法即可),允许使用的运算符包括加减乘除和括号(允许对参数的顺序进行调整)。

通常来说最初考虑的算法就是穷举法:

function equalTo24(a,b,c,d){
let arrayList = [a, b, c, d];
//构造所有数据的排列组合集合
let arrayRe = combination(arrayList);
//构造所有运算符的排列组合集合(由于括号运算符的特殊性,故当前只考虑4个数据时的情况)
var operatorList = [];//operatorList元素长度为3(长度比arrayList少1)
if (operatorList.length === 0) {
//全部运算符是加减(无须考虑括号,因为arrayRe是全部集合,因此+-+必定有++-结果相同的情况,因为元素位置可以变化)
operatorList.push(["+", "+", "+"]);
operatorList.push(["+", "+", "-"]);
operatorList.push(["+", "-", "-"]);
operatorList.push(["-", "-", "-"]);
//全部运算符是乘除(无须考虑括号,只有4种情况原因如上)
operatorList.push(["*", "*", "*"]);
operatorList.push(["*", "*", "/"]);
operatorList.push(["*", "/", "/"]);
operatorList.push(["/", "/", "/"]);
//一个运算符是加减 两个运算符是乘除
operatorList.push(["+", "*", "*"]);
operatorList.push(["(+", ")*", "*"]);
operatorList.push(["(+", "*", ")*"]);
operatorList.push(["+", "*", "/"]);
operatorList.push(["(+", ")*", "/"]);
operatorList.push(["(+", "*", ")/"]);
operatorList.push(["+", "/", "*"]);
operatorList.push(["(+", "/", ")*"]);
operatorList.push(["+", "/", "/"]);
operatorList.push(["(+", ")/", "/"]);
operatorList.push(["(+", "/", ")/"]);
operatorList.push(["-", "*", "*"]);
operatorList.push(["(-", ")*", "*"]);
operatorList.push(["(-", "*", ")*"]);
operatorList.push(["-", "*", "/"]);
operatorList.push(["(-", ")*", "/"]);
operatorList.push(["(-", "*", ")/"]);
operatorList.push(["-", "/", "*"]);
operatorList.push(["(-", "/", ")*"]);
operatorList.push(["-", "/", "/"]);
operatorList.push(["(-", ")/", "/"]);
operatorList.push(["(-", "/", ")/"]);

operatorList.push(["*", "+", "*"]);
operatorList.push(["*", "-", "*"]);
operatorList.push(["(*", "-", ")*"]);
operatorList.push(["/", "+", "*"]);
operatorList.push(["/(", "+", ")*"]);
operatorList.push(["(/", "+", ")*"]);
operatorList.push(["/(", "+", "*)"]);
operatorList.push(["/", "-", "*"]);
operatorList.push(["/(", "-", ")*"]);
operatorList.push(["(/", "-", ")*"]);
operatorList.push(["/(", "-", "*)"]);
operatorList.push(["*", "+", "/"]);
operatorList.push(["*(", "+", ")/"]);
operatorList.push(["(*", "+", ")/"]);
operatorList.push(["*(", "+", "/)"]);
operatorList.push(["*", "-", "/"]);
operatorList.push(["*(", "-", ")/"]);
operatorList.push(["(*", "-", ")/"]);
operatorList.push(["*(", "-", "/)"]);
operatorList.push(["/", "+", "/"]);
operatorList.push(["/(", "+", ")/"]);
operatorList.push(["(/", "+", ")/"]);
operatorList.push(["/(", "+", "/)"]);
operatorList.push(["/", "-", "/"]);
operatorList.push(["/(", "-", ")/"]);
operatorList.push(["(/", "-", ")/"]);
operatorList.push(["/(", "-", "/)"]);

operatorList.push(["*", "*", "-"]);
operatorList.push(["*", "/", "+"]);
operatorList.push(["*", "/(", "+)"]);
operatorList.push(["*(", "/", "+)"]);
operatorList.push(["*", "/", "-"]);
operatorList.push(["*", "/(", "-)"]);
operatorList.push(["/(", "*", "+)"]);
operatorList.push(["/", "*", "-"]);
operatorList.push(["/(", "*", "-)"]);
operatorList.push(["/", "/", "+"]);
operatorList.push(["/", "/(", "+)"]);
operatorList.push(["/(", "/", "+)"]);
operatorList.push(["/", "/", "-"]);
operatorList.push(["/", "/(", "-)"]);
operatorList.push(["/(", "/", "-)"]);
//两个运算符是加减 一个运算符是乘除
operatorList.push(["+", "*", "+"]);
operatorList.push(["+", "*", "-"]);
operatorList.push(["+", "/", "+"]);
operatorList.push(["+", "/", "-"]);
operatorList.push(["-", "*", "+"]);
operatorList.push(["-", "*", "-"]);
operatorList.push(["-", "/", "+"]);
operatorList.push(["-", "/", "-"]);

operatorList.push(["(+", ")*", "+"]);
operatorList.push(["(+", ")*", "-"]);
operatorList.push(["(+", ")/", "+"]);
operatorList.push(["(+", ")/", "-"]);
operatorList.push(["(-", ")*", "+"]);
operatorList.push(["(-", ")*", "-"]);
operatorList.push(["(-", ")/", "+"]);
operatorList.push(["(-", ")/", "-"]);

operatorList.push(["+", "/(", "+)"]);
operatorList.push(["+", "/(", "-)"]);
operatorList.push(["-", "*(", "+)"]);
operatorList.push(["-", "*(", "-)"]);
operatorList.push(["-", "/(", "+)"]);
operatorList.push(["-", "/(", "-)"]);

operatorList.push(["(+", ")*(", "+)"]);
operatorList.push(["(+", ")*(", "-)"]);
operatorList.push(["(+", ")/(", "+)"]);
operatorList.push(["(+", ")/(", "-)"]);
operatorList.push(["(-", ")*(", "-)"]);
operatorList.push(["(-", ")/(", "+)"]);
operatorList.push(["(-", ")/(", "-)"]);

operatorList.push(["*", "-", "-"]);
operatorList.push(["/", "-", "-"]);

operatorList.push(["/(", "+", ")-"]);
operatorList.push(["/(", "-", ")-"]);

operatorList.push(["*(", "+", "+)"]);
operatorList.push(["*(", "+", "-)"]);
operatorList.push(["*(", "-", "+)"]);
operatorList.push(["*(", "-", "-)"]);
operatorList.push(["/(", "+", "+)"]);
operatorList.push(["/(", "+", "-)"]);
operatorList.push(["/(", "-", "+)"]);
operatorList.push(["/(", "-", "-)"]);

operatorList.push(["-", "-", "*"]);
operatorList.push(["-", "-", "/"]);

operatorList.push(["-(", "+", ")*"]);
operatorList.push(["-(", "-", ")*"]);
operatorList.push(["-(", "+", ")/"]);
operatorList.push(["-(", "-", ")/"]);

operatorList.push(["(+", "+", ")/"]);
operatorList.push(["(+", "-", ")/"]);
operatorList.push(["(-", "+", ")/"]);
operatorList.push(["(-", "-", ")/"]);
}

for (let i = 0; i < operatorList.length; i++) {
let oper = operatorList[i];
let begin = "";
let end = "";
if (oper[0].indexOf("(") === 0) {
begin = "(";
oper[0] = oper[0].substr(1);
}
if (oper[2].indexOf(")") === 1) {
end = ")";
oper[2] = oper[2].substr(0, 1);
}
for (let j = 0; j < arrayRe.length; j++) {
let arrList = arrayRe[j].split(" ");

let str = begin + parseInt(arrList[0]) + oper[0] + parseInt(arrList[1]) + oper[1] + parseInt(arrList[2]) + oper[2] + parseInt(arrList[3]) + end;
if (eval(str) === 24) {
return str;
}
}

}

return "It's not possible!";
}

function combination(list) {
if (list.length > 1) {
let result = [];
for (let i = 0; i < list.length; i++) {
let current = list[i];
let newList = [];
for (let j = 0; j < list.length; j++) {
if (i !== j) {
newList.push(list[j]);
}
}
let next = combination(newList);
next.forEach(function(item) {
result.push("" + current + " " + item);
});
}
return result;
} else {
return [list[0] + ""];
}
}


算法理解:首先找出所有参数排列组合集合,然后找出所有运算符排列组合集合(这里做了去重优化,如c * (a + b) - d的结果和(a + b) * c - d的结果是一样的,则其中一个运算符排列组合是无意义的,可以从集合中去掉),最后拼接成完整的字符串运算表达式,然后用eval函数执行,当计算结果为24则返回当前的运算表达式。

即使穷举法对运算符的排列组合进行了一定优化,但是仍然存在2个严重问题:

运算符排列组合依赖人工穷举和优化,穷举容易出错(尤其是括号的存在增加了大量组合方式),优化容易发生遗漏,且难以维护;

运算符排列组合限制了函数的扩展,如函数调整为5个参数计算24点,则穷举排列组合部分的大量代码全部需要重写。

针对上面几个问题进行第一次优化,下面上优化代码:

function equalTo24(a,b,c,d){
return getResult([a,b,c,d]);
}

function getResult (list) {
for (let i = 0; i < list.length; i++) {
let currentA = list[i];
let newList = [];
for (let j = i + 1; j < list.length; j++) {
let currentB = list[j];
let exp1 = "(" + currentA + "+" + currentB + ")";
let exp2 = "(" + currentA + "-" + currentB + ")";
let exp3 = "(" + currentB + "-" + currentA + ")";
let exp4 = "(" + currentA + "*" + currentB + ")";
let exp5 = "(" + currentA + "/" + currentB + ")";
let exp6 = "(" + currentB + "/" + currentA + ")";
if (list.length === 2) {
if (Math.abs(eval(exp1) - 24) < 0.00000000001) return exp1;
if (Math.abs(eval(exp2) - 24) < 0.00000000001) return exp2;
if (Math.abs(eval(exp3) - 24) < 0.00000000001) return exp3;
if (Math.abs(eval(exp4) - 24) < 0.00000000001) return exp4;
if (Math.abs(eval(exp5) - 24) < 0.00000000001) return exp5;
if (Math.abs(eval(exp6) - 24) < 0.00000000001) return exp6;
return "It's not possible!";
} else {
let leftList = [];
for (let k = 0; k < list.length; k++) {
if (k !== j && k !== i) {
leftList.push(list[k]);
}
}
let newexp1 = [exp1].concat(leftList);
let newexp2 = [exp2].concat(leftList);
let newexp3 = [exp3].concat(leftList);
let newexp4 = [exp4].concat(leftList);
let newexp5 = [exp5].concat(leftList);
let newexp6 = [exp6].concat(leftList);
let r1 = getResult(newexp1);
if (r1 !== "It's not possible!") {
return r1;
}
let r2 = getResult(newexp2);
if (r2 !== "It's not possible!") {
return r2;
}
let r3 = getResult(newexp3);
if (r3 !== "It's not possible!") {
return r3;
}
let r4 = getResult(newexp4);
if (r4 !== "It's not possible!") {
return r4;
}
let r5 = getResult(newexp5);
if (r5 !== "It's not possible!") {
return r5;
}
let r6 = getResult(newexp6);
if (r6 !== "It's not possible!") {
return r6;
}
}
}
}
return "It's not possible!";
}


算法理解:从参数集合中任取2个参数拼接成运算表达式,然后与剩下的参数组合成新的参数集合进行递归,直到参数集合中只有2个参数时,用eval函数执行最终的运算表达式,当计算结果为24则返回当前的运算表达式。

上面的算法与穷举法相比无论从代码可维护性、可读性还是简洁程度上都有了明显提示,但仍然存在一个问题:

使用了eval函数,eval函数属于高风险函数,如果函数参数来源不可信,则容易受到注入攻击,另外,eval函数的频繁使用也使函数性能有所下降。

针对eval再次优化:

function equalTo24(a,b,c,d){
return getResult([a,b,c,d], [""+a,""+b,""+c,""+d]);
}

function getResult (list, expList) {
for (let i = 0; i < list.length; i++) {
let currentA = list[i];
let expA = expList[i];
let newList = [];
for (let j = i + 1; j < list.length; j++) {
let currentB = list[j];
let expB = expList[j];
let exp1 = "(" + expA + "+" + expB + ")";
let exp2 = "(" + expA + "-" + expB + ")";
let exp3 = "(" + expB + "-" + expA + ")";
let exp4 = "(" + expA + "*" + expB + ")";
let exp5 = "(" + expA + "/" + expB + ")";
let exp6 = "(" + expB + "/" + expA + ")";

let cur1 = currentA + currentB;
let cur2 = currentA - currentB;
let cur3 = currentB - currentA;
let cur4 = currentA * currentB;
let cur5 = currentA / currentB;
let cur6 = currentB / currentA;
if (list.length === 2) {
if (Math.abs(cur1 - 24) < 0.00000000001) return exp1;
if (Math.abs(cur2 - 24) < 0.00000000001) return exp2;
if (Math.abs(cur3 - 24) < 0.00000000001) return exp3;
if (Math.abs(cur4 - 24) < 0.00000000001) return exp4;
if (Math.abs(cur5 - 24) < 0.00000000001) return exp5;
if (Math.abs(cur6 - 24) < 0.00000000001) return exp6;
return "It's not possible!";
} else {
let leftList = [];
for (let k = 0; k < list.length; k++) {
if (k !== j && k !== i) {
leftList.push(list[k]);
}
}
let leftExpList = [];
for (let k = 0; k < expList.length; k++) {
if (k !== j && k !== i) {
leftExpList.push(expList[k]);
}
}
let newexp1 = [exp1].concat(leftExpList);
let newexp2 = [exp2].concat(leftExpList);
let newexp3 = [exp3].concat(leftExpList);
let newexp4 = [exp4].concat(leftExpList);
let newexp5 = [exp5].concat(leftExpList);
let newexp6 = [exp6].concat(leftExpList);

let newlist1 = [cur1].concat(leftList);
let newlist2 = [cur2].concat(leftList);
let newlist3 = [cur3].concat(leftList);
let newlist4 = [cur4].concat(leftList);
let newlist5 = [cur5].concat(leftList);
let newlist6 = [cur6].concat(leftList);
let r1 = getResult(newlist1, newexp1);
if (r1 !== "It's not possible!") {
return r1;
}
let r2 = getResult(newlist2, newexp2);
if (r2 !== "It's not possible!") {
return r2;
}
let r3 = getResult(newlist3, newexp3);
if (r3 !== "It's not possible!") {
return r3;
}
let r4 = getResult(newlist4, newexp4);
if (r4 !== "It's not possible!") {
return r4;
}
let r5 = getResult(newlist5, newexp5);
if (r5 !== "It's not possible!") {
return r5;
}
let r6 = getResult(newlist6, newexp6);
if (r6 !== "It's not possible!") {
return r6;
}
}
}
}
return "It's not possible!";
}


算法理解:算法思路未改变,只是在拼接运算表达式时,参与计算的是运算表达式的结果(这样也就不再需要eval了),而返回的则是字符串运算表达式。

接下来是性能比较,比较代码:

//穷举法
function equalTo24A(a,b,c,d){
let arrayList = [a, b, c, d];
//构造所有数据的排列组合集合
let arrayRe = combination(arrayList);
//构造所有运算符的排列组合集合(由于括号运算符的特殊性,故当前只考虑4个数据时的情况)
var operatorList = [];//operatorList元素长度为3(长度比arrayList少1)
if (operatorList.length === 0) {
//全部运算符是加减(无须考虑括号,因为arrayRe是全部集合,因此+-+必定有++-结果相同的情况,因为元素位置可以变化)
operatorList.push(["+", "+", "+"]);
operatorList.push(["+", "+", "-"]);
operatorList.push(["+", "-", "-"]);
operatorList.push(["-", "-", "-"]);
//全部运算符是乘除(无须考虑括号,只有4种情况原因如上)
operatorList.push(["*", "*", "*"]);
operatorList.push(["*", "*", "/"]);
operatorList.push(["*", "/", "/"]);
operatorList.push(["/", "/", "/"]);
//一个运算符是加减 两个运算符是乘除
operatorList.push(["+", "*", "*"]);
operatorList.push(["(+", ")*", "*"]);
operatorList.push(["(+", "*", ")*"]);
operatorList.push(["+", "*", "/"]);
operatorList.push(["(+", ")*", "/"]);
operatorList.push(["(+", "*", ")/"]);
operatorList.push(["+", "/", "*"]);
operatorList.push(["(+", "/", ")*"]);
operatorList.push(["+", "/", "/"]);
operatorList.push(["(+", ")/", "/"]);
operatorList.push(["(+", "/", ")/"]);
operatorList.push(["-", "*", "*"]);
operatorList.push(["(-", ")*", "*"]);
operatorList.push(["(-", "*", ")*"]);
operatorList.push(["-", "*", "/"]);
operatorList.push(["(-", ")*", "/"]);
operatorList.push(["(-", "*", ")/"]);
operatorList.push(["-", "/", "*"]);
operatorList.push(["(-", "/", ")*"]);
operatorList.push(["-", "/", "/"]);
operatorList.push(["(-", ")/", "/"]);
operatorList.push(["(-", "/", ")/"]);

operatorList.push(["*", "+", "*"]);
operatorList.push(["*", "-", "*"]);
operatorList.push(["(*", "-", ")*"]);
operatorList.push(["/", "+", "*"]);
operatorList.push(["/(", "+", ")*"]);
operatorList.push(["(/", "+", ")*"]);
operatorList.push(["/(", "+", "*)"]);
operatorList.push(["/", "-", "*"]);
operatorList.push(["/(", "-", ")*"]);
operatorList.push(["(/", "-", ")*"]);
operatorList.push(["/(", "-", "*)"]);
operatorList.push(["*", "+", "/"]);
operatorList.push(["*(", "+", ")/"]);
operatorList.push(["(*", "+", ")/"]);
operatorList.push(["*(", "+", "/)"]);
operatorList.push(["*", "-", "/"]);
operatorList.push(["*(", "-", ")/"]);
operatorList.push(["(*", "-", ")/"]);
operatorList.push(["*(", "-", "/)"]);
operatorList.push(["/", "+", "/"]);
operatorList.push(["/(", "+", ")/"]);
operatorList.push(["(/", "+", ")/"]);
operatorList.push(["/(", "+", "/)"]);
operatorList.push(["/", "-", "/"]);
operatorList.push(["/(", "-", ")/"]);
operatorList.push(["(/", "-", ")/"]);
operatorList.push(["/(", "-", "/)"]);

operatorList.push(["*", "*", "-"]);
operatorList.push(["*", "/", "+"]);
operatorList.push(["*", "/(", "+)"]);
operatorList.push(["*(", "/", "+)"]);
operatorList.push(["*", "/", "-"]);
operatorList.push(["*", "/(", "-)"]);
operatorList.push(["/(", "*", "+)"]);
operatorList.push(["/", "*", "-"]);
operatorList.push(["/(", "*", "-)"]);
operatorList.push(["/", "/", "+"]);
operatorList.push(["/", "/(", "+)"]);
operatorList.push(["/(", "/", "+)"]);
operatorList.push(["/", "/", "-"]);
operatorList.push(["/", "/(", "-)"]);
operatorList.push(["/(", "/", "-)"]);
//两个运算符是加减 一个运算符是乘除
operatorList.push(["+", "*", "+"]);
operatorList.push(["+", "*", "-"]);
operatorList.push(["+", "/", "+"]);
operatorList.push(["+", "/", "-"]);
operatorList.push(["-", "*", "+"]);
operatorList.push(["-", "*", "-"]);
operatorList.push(["-", "/", "+"]);
operatorList.push(["-", "/", "-"]);

operatorList.push(["(+", ")*", "+"]);
operatorList.push(["(+", ")*", "-"]);
operatorList.push(["(+", ")/", "+"]);
operatorList.push(["(+", ")/", "-"]);
operatorList.push(["(-", ")*", "+"]);
operatorList.push(["(-", ")*", "-"]);
operatorList.push(["(-", ")/", "+"]);
operatorList.push(["(-", ")/", "-"]);

operatorList.push(["+", "/(", "+)"]);
operatorList.push(["+", "/(", "-)"]);
operatorList.push(["-", "*(", "+)"]);
operatorList.push(["-", "*(", "-)"]);
operatorList.push(["-", "/(", "+)"]);
operatorList.push(["-", "/(", "-)"]);

operatorList.push(["(+", ")*(", "+)"]);
operatorList.push(["(+", ")*(", "-)"]);
operatorList.push(["(+", ")/(", "+)"]);
operatorList.push(["(+", ")/(", "-)"]);
operatorList.push(["(-", ")*(", "-)"]);
operatorList.push(["(-", ")/(", "+)"]);
operatorList.push(["(-", ")/(", "-)"]);

operatorList.push(["*", "-", "-"]);
operatorList.push(["/", "-", "-"]);

operatorList.push(["/(", "+", ")-"]);
operatorList.push(["/(", "-", ")-"]);

operatorList.push(["*(", "+", "+)"]);
operatorList.push(["*(", "+", "-)"]);
operatorList.push(["*(", "-", "+)"]);
operatorList.push(["*(", "-", "-)"]);
operatorList.push(["/(", "+", "+)"]);
operatorList.push(["/(", "+", "-)"]);
operatorList.push(["/(", "-", "+)"]);
operatorList.push(["/(", "-", "-)"]);

operatorList.push(["-", "-", "*"]);
operatorList.push(["-", "-", "/"]);

operatorList.push(["-(", "+", ")*"]);
operatorList.push(["-(", "-", ")*"]);
operatorList.push(["-(", "+", ")/"]);
operatorList.push(["-(", "-", ")/"]);

operatorList.push(["(+", "+", ")/"]);
operatorList.push(["(+", "-", ")/"]);
operatorList.push(["(-", "+", ")/"]);
operatorList.push(["(-", "-", ")/"]);
}

for (let i = 0; i < operatorList.length; i++) {
let oper = operatorList[i];
let begin = "";
let end = "";
if (oper[0].indexOf("(") === 0) {
begin = "(";
oper[0] = oper[0].substr(1);
}
if (oper[2].indexOf(")") === 1) {
end = ")";
oper[2] = oper[2].substr(0, 1);
}
for (let j = 0; j < arrayRe.length; j++) {
let arrList = arrayRe[j].split(" ");

let str = begin + parseInt(arrList[0]) + oper[0] + parseInt(arrList[1]) + oper[1] + parseInt(arrList[2]) + oper[2] + parseInt(arrList[3]) + end;
if (eval(str) === 24) {
return str;
}
}

}

return "It's not possible!";
}

function combination(list) {
if (list.length > 1) {
let result = [];
for (let i = 0; i < list.length; i++) {
let current = list[i];
let newList = [];
for (let j = 0; j < list.length; j++) {
if (i !== j) {
newList.push(list[j]);
}
}
let next = combination(newList);
next.forEach(function(item) {
result.push("" + current + " " + item);
});
}
return result;
} else {
return [list[0] + ""];
}
}

//优化一
function equalTo24B(a,b,c,d){
return getResultB([a,b,c,d]);
}

function getResultB (list) {
for (let i = 0; i < list.length; i++) {
let currentA = list[i];
let newList = [];
for (let j = i + 1; j < list.length; j++) {
let currentB = list[j];
let exp1 = "(" + currentA + "+" + currentB + ")";
let exp2 = "(" + currentA + "-" + currentB + ")";
let exp3 = "(" + currentB + "-" + currentA + ")";
let exp4 = "(" + currentA + "*" + currentB + ")";
let exp5 = "(" + currentA + "/" + currentB + ")";
let exp6 = "(" + currentB + "/" + currentA + ")";
if (list.length === 2) {
if (Math.abs(eval(exp1) - 24) < 0.00000000001) return exp1;
if (Math.abs(eval(exp2) - 24) < 0.00000000001) return exp2;
if (Math.abs(eval(exp3) - 24) < 0.00000000001) return exp3;
if (Math.abs(eval(exp4) - 24) < 0.00000000001) return exp4;
if (Math.abs(eval(exp5) - 24) < 0.00000000001) return exp5;
if (Math.abs(eval(exp6) - 24) < 0.00000000001) return exp6;
return "It's not possible!";
} else {
let leftList = [];
for (let k = 0; k < list.length; k++) {
if (k !== j && k !== i) {
leftList.push(list[k]);
}
}
let newexp1 = [exp1].concat(leftList);
let newexp2 = [exp2].concat(leftList);
let newexp3 = [exp3].concat(leftList);
let newexp4 = [exp4].concat(leftList);
let newexp5 = [exp5].concat(leftList);
let newexp6 = [exp6].concat(leftList);
let r1 = getResultB(newexp1);
if (r1 !== "It's not possible!") {
return r1;
}
let r2 = getResultB(newexp2);
if (r2 !== "It's not possible!") {
return r2;
}
let r3 = getResultB(newexp3);
if (r3 !== "It's not possible!") {
return r3;
}
let r4 = getResultB(newexp4);
if (r4 !== "It's not possible!") {
return r4;
}
let r5 = getResultB(newexp5);
if (r5 !== "It's not possible!") {
return r5;
}
let r6 = getResultB(newexp6);
if (r6 !== "It's not possible!") {
return r6;
}
}
}
}
return "It's not possible!";
}

//优化二
function equalTo24C(a,b,c,d){
return getResultC([a,b,c,d], [""+a,""+b,""+c,""+d]);
}

function getResultC (list, expList) {
for (let i = 0; i < list.length; i++) {
let currentA = list[i];
let expA = expList[i];
let newList = [];
for (let j = i + 1; j < list.length; j++) {
let currentB = list[j];
let expB = expList[j];
let exp1 = "(" + expA + "+" + expB + ")";
let exp2 = "(" + expA + "-" + expB + ")";
let exp3 = "(" + expB + "-" + expA + ")";
let exp4 = "(" + expA + "*" + expB + ")";
let exp5 = "(" + expA + "/" + expB + ")";
let exp6 = "(" + expB + "/" + expA + ")";

let cur1 = currentA + currentB;
let cur2 = currentA - currentB;
let cur3 = currentB - currentA;
let cur4 = currentA * currentB;
let cur5 = currentA / currentB;
let cur6 = currentB / currentA;
if (list.length === 2) {
if (Math.abs(cur1 - 24) < 0.00000000001) return exp1;
if (Math.abs(cur2 - 24) < 0.00000000001) return exp2;
if (Math.abs(cur3 - 24) < 0.00000000001) return exp3;
if (Math.abs(cur4 - 24) < 0.00000000001) return exp4;
if (Math.abs(cur5 - 24) < 0.00000000001) return exp5;
if (Math.abs(cur6 - 24) < 0.00000000001) return exp6;
return "It's not possible!";
} else {
let leftList = [];
for (let k = 0; k < list.length; k++) {
if (k !== j && k !== i) {
leftList.push(list[k]);
}
}
let leftExpList = [];
for (let k = 0; k < expList.length; k++) {
if (k !== j && k !== i) {
leftExpList.push(expList[k]);
}
}
let newexp1 = [exp1].concat(leftExpList);
let newexp2 = [exp2].concat(leftExpList);
let newexp3 = [exp3].concat(leftExpList);
let newexp4 = [exp4].concat(leftExpList);
let newexp5 = [exp5].concat(leftExpList);
let newexp6 = [exp6].concat(leftExpList);

let newlist1 = [cur1].concat(leftList);
let newlist2 = [cur2].concat(leftList);
let newlist3 = [cur3].concat(leftList);
let newlist4 = [cur4].concat(leftList);
let newlist5 = [cur5].concat(leftList);
let newlist6 = [cur6].concat(leftList);
let r1 = getResultC(newlist1, newexp1);
if (r1 !== "It's not possible!") {
return r1;
}
let r2 = getResultC(newlist2, newexp2);
if (r2 !== "It's not possible!") {
return r2;
}
let r3 = getResultC(newlist3, newexp3);
if (r3 !== "It's not possible!") {
return r3;
}
let r4 = getResultC(newlist4, newexp4);
if (r4 !== "It's not possible!") {
return r4;
}
let r5 = getResultC(newlist5, newexp5);
if (r5 !== "It's not possible!") {
return r5;
}
let r6 = getResultC(newlist6, newexp6);
if (r6 !== "It's not possible!") {
return r6;
}
}
}
}
return "It's not possible!";
}

let start = new Date().getTime();
console.log(equalTo24A(29, 23, 23, 23));
let end = new Date().getTime();
console.log("equalTo24A used time is " + (end - start));

start = new Date().getTime();
console.log(equalTo24B(29, 23, 23, 23));
end = new Date().getTime();
console.log("equalTo24B used time is " + (end - start));

start = new Date().getTime();
console.log(equalTo24C(29, 23, 23, 23));
end = new Date().getTime();
console.log("equalTo24C used time is " + (end - start));


用一个无可行算法的参数集合来验证三种方法的用时(无可行算法用于保证函数会完整运行而不是在找到可行算法后返回):

验证次数穷举法用时第一次优化用时第二次优化用时
第一次2663054
第二次2493025
第三次2693066
第一次:



第二次:



第三次:



总结:第一次优化后函数性能有小幅下降,但可读性、可维护性都有大幅上升,在工程开发中这种做法是应当鼓励的;而第二次优化后性能大幅上升,没有别的,牢记一点:永远不要在循环中使用eval函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  javascript 算法 24点