繁体   English   中英

为什么这个递归函数会跳过数字?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM