[英]Why does this recursive function skip numbers?
我试图用数字1-9找到等于100的各种可能性。 这个功能可以产生预期的效果,但也有其他我没想过的结果。 其他结果加起来为100,但没有这些数字,比如省略3或6.为什么包含这些其他结果?
var nums = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var signs = ["+", "-", "N"];
var results = [];
find100("1");
function find100(expr) {
if (eval(expr.replace(/N/g, "")) === 100) {
results.push(expr);
} else {
for (var i = eval(expr.substring(expr.length - 1, expr.length)) + 1; i <=
nums.length; i++) {
signs.forEach(function(sign) {
var expr2 = expr;
find100(expr2 += sign + i);
});
}
}
}
期望的输出:
1+2+3-4+5+6+78+9,
1+2+34-5+67-8+9,
1+23-4+5+6+78-9,
1+23-4+56+7+8+9,
12+3+4+5-6-7+89,
12+3-4+5+67+8+9,
12-3-4+5-6+7+89,
123+4-5+67-89,
123+45-67+8-9,
123-4-5-6-7+8-9,
123-45-67+89
它会添加不需要的结果,因为您的第一个循环遍历每个剩余数字并添加任意结果,评估为100,即使它已跳过一个数字来执行此操作。 如果该方法找到一个数字的解决方案,它会将解决方案添加到results
- 这是正确的,但是如果它找不到解决方案,则无论如何都会移动到下一个数字。 这是跳过的数字的来源。 如果没有数字的解决方案,它应该没有继续下一个数字。
至于如何修复它,这是一个不同的问题(但为什么不......)
这里的区别在于,如果任何数字存在使用所有剩余数字的表达式,则只能获得结果。
var results = []; var operations = [ "+", "-", "" ]; var expected = 100; var limit = 10; function findExpression(expr, next) { if (next === limit) { eval(expr) === expected && results.push(expr); } else { operations.forEach(function(operation) { findExpression(expr + operation + next, next + 1); }); } } $(document).ready(function() { findExpression("1", 2); for(var i=0; i<results.length; i++) { $("#foo").append(results[i]+"<br />"); } });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script> <body> <div id="foo"></div> </body>
跳过某些数字的原因是在这个循环中:
for (var i = eval(expr.substring(expr.length - 1, expr.length)) + 1; i <=
nums.length; i++) {
在第二次迭代时,它将递增表达式中的最后一个数字,这将在连续递归中产生间隙。 简而言之,那个循环不应该存在。
我建议不使用eval
的解决方案,不是因为它会有某种危险,而是因为它是造成重大性能损失的原因。
相反,您可以将数值变量更新为表达式所代表的内容。 实际上,我建议使用两个这样的变量,一个用于前一个术语的总和,另一个用于最后一个术语,因为可能需要使用更多数字来扩展。
为了促进符号影响表达式的不同方式,我已经为每个符号定义了一个函数:它采用上面提到的数值,也是最后一个数字,并返回更新的值。
这是一个使用该想法的工作片段(ES6语法),您会注意到性能的显着改善:
function find100(digits, signs) { const loop = (expr, i, [sum, value]) => // Not yet all digits used? i < digits.length ? // Apply each of the signs in turn: Object.keys(signs).reduce( (results, sign) => // Recurse, passing on the modified expression, the sum of the // preceding terms, and the value of the last term. As '+' is // not any different than '' before the first digit, skip '+': sign != '+' || i ? results.concat(loop(expr+sign+digits[i], i+1, signs[sign](sum, value, digits[i]))) : results, [] ) : // All digits were used. Did it match? sum+value == 100 ? [expr] : []; // Start recursion return loop('', 0, [0, 0]); } var nums = [1, 2, 3, 4, 5, 6, 7, 8, 9]; // define how each sign should modify the expression value: var signs = { '+': (sum, value, digit) => [sum+value, digit], '-': (sum, value, digit) => [sum+value, -digit], '' : (sum, value, digit) => [sum, value*10 + (value<0 ? -digit : digit)] }; var results = find100(nums, signs); console.log(results);
请注意,这也输出以下表达式:
-1+2-3+4+5+6+78+9
这是因为代码也在第一个数字之前尝试符号。 我认为这也包含在输出中是有意义的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.