算法性能比较(三)——24点算法优化(怎么从low到爆变成唉哟不错哦)
2018-03-12 11:27
381 查看
原题简单描述如下:
给定4个参数(参数为整数,范围为1-100),以最快的速度找出对应的24点算法(无需找到全部算法,只要找到任意一个可行算法即可),允许使用的运算符包括加减乘除和括号(允许对参数的顺序进行调整)。
通常来说最初考虑的算法就是穷举法:
算法理解:首先找出所有参数排列组合集合,然后找出所有运算符排列组合集合(这里做了去重优化,如c * (a + b) - d的结果和(a + b) * c - d的结果是一样的,则其中一个运算符排列组合是无意义的,可以从集合中去掉),最后拼接成完整的字符串运算表达式,然后用eval函数执行,当计算结果为24则返回当前的运算表达式。
即使穷举法对运算符的排列组合进行了一定优化,但是仍然存在2个严重问题:
运算符排列组合依赖人工穷举和优化,穷举容易出错(尤其是括号的存在增加了大量组合方式),优化容易发生遗漏,且难以维护;
运算符排列组合限制了函数的扩展,如函数调整为5个参数计算24点,则穷举排列组合部分的大量代码全部需要重写。
针对上面几个问题进行第一次优化,下面上优化代码:
算法理解:从参数集合中任取2个参数拼接成运算表达式,然后与剩下的参数组合成新的参数集合进行递归,直到参数集合中只有2个参数时,用eval函数执行最终的运算表达式,当计算结果为24则返回当前的运算表达式。
上面的算法与穷举法相比无论从代码可维护性、可读性还是简洁程度上都有了明显提示,但仍然存在一个问题:
使用了eval函数,eval函数属于高风险函数,如果函数参数来源不可信,则容易受到注入攻击,另外,eval函数的频繁使用也使函数性能有所下降。
针对eval再次优化:
算法理解:算法思路未改变,只是在拼接运算表达式时,参与计算的是运算表达式的结果(这样也就不再需要eval了),而返回的则是字符串运算表达式。
接下来是性能比较,比较代码:
用一个无可行算法的参数集合来验证三种方法的用时(无可行算法用于保证函数会完整运行而不是在找到可行算法后返回):
第一次:
第二次:
第三次:
总结:第一次优化后函数性能有小幅下降,但可读性、可维护性都有大幅上升,在工程开发中这种做法是应当鼓励的;而第二次优化后性能大幅上升,没有别的,牢记一点:永远不要在循环中使用eval函数。
给定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));
用一个无可行算法的参数集合来验证三种方法的用时(无可行算法用于保证函数会完整运行而不是在找到可行算法后返回):
验证次数 | 穷举法用时 | 第一次优化用时 | 第二次优化用时 |
---|---|---|---|
第一次 | 266 | 305 | 4 |
第二次 | 249 | 302 | 5 |
第三次 | 269 | 306 | 6 |
第二次:
第三次:
总结:第一次优化后函数性能有小幅下降,但可读性、可维护性都有大幅上升,在工程开发中这种做法是应当鼓励的;而第二次优化后性能大幅上升,没有别的,牢记一点:永远不要在循环中使用eval函数。
相关文章推荐
- 算法8:一个整数数组里怎么同时找最大和最小的数,尽量优化比较次数
- 【SQL Server性能优化】删除大量数据的方法比较
- Java不同压缩算法的性能比较
- 常用推荐算法性能比较
- ASP.NET比较常用的26个性能优化技巧
- ASP.NET比较常用的26个性能优化技巧
- 算法分析(总结)排序算法性能及比较总结
- Mysql数据库服务器性能配置优化二 -- 文件系统及IO调度算法的选择
- 性能优化之无阻塞加载脚步方法比较
- Java不同压缩算法的性能比较
- 常用推荐算法性能比较
- 怎么优化JAVA程序的执行效率和性能?
- ASP.NET比较常用的26个性能优化技巧
- CCS下优化的c文件和asm文件被codec engine调用性能比较
- 优化反射性能比较
- 案例-js-模块化创建dom与字符串创建dom的耗时比较(性能优化)
- ASP.NET比较常用的26个性能优化技巧
- Java不同压缩算法的性能比较
- 网站优化-HTTP REQUEST与web service 性能测试比较
- 【Hibernate框架开发之九】Hibernate 性能优化笔记!(遍历、一级/二级/查询/缓存、乐观悲观锁等优化算法)