【问题标题】:How to implement recursive algorithm correctly?如何正确实现递归算法?
【发布时间】:2017-02-26 08:44:36
【问题描述】:

我正在尝试解决 codewars 网站上的算法。作为初学者,我很难实现各种编程技术,并且缺乏基本的编程概念,例如作用域、提升等。无论如何,我决心解决这个问题。

说明书说:

编写一个函数,persistence,它接受一个正参数 num 并返回它的乘法持久性,即你必须将 num 中的数字相乘直到达到一个数字的次数。 em>

persistence(39) === 3 // because 3*9 = 27, 2*7 = 14, 1*4=4
                           // and 4 has only one digit
persistence(999) === 4 // because 9*9*9 = 729, 7*2*9 = 126,
                            // 1*2*6 = 12, and finally 1*2 = 2
persistence(4) === 0 // because 4 is already a one-digit number

现在我只想达到这个结果3*9 = 27, 2*7 = 14, 1*4=4 但是我卡住了。我知道我错过了什么,请给我一些宝贵的建议!

我的代码如下所示:

function persistence(num) {
    var total = 1;
    var step = 0;
    var number = multiple(num);
    while (step < 3) {
        for (var i = 0; i < number.length; i++) {
            total *= splitNumbers[i];
        }
        multiple(number);
        step += 1;
    }
}

function multiple(num) {
    var splitNumbers = num.toString().split('');
    var a = splitNumbers[0];
    var b = splitNumbers[1];
    return a * b;
}
persistence(39);

【问题讨论】:

  • number 是一个数字。数字没有长度属性,因此i &lt; number.length 会将 i 的值设置为未定义。顺便说一句,这不是递归。 ;-)
  • 好的,谢谢,我没注意到))

标签: javascript algorithm


【解决方案1】:

奇怪的是,在第二个函数中计算一个乘积(忽略除前两个之外的所有数字),然后在主函数中将其视为一个字符串(它不是),并开始将这些乘积又是数字。这不是递归的原则:您应该只执行一次操作,然后执行递归调用。

这是一个解决方案:

function persistence(num) {
    var digits = getDigits(num);
    if (digits.length === 1) return 0; // number has only 1 digit, so we're done
    var product = getProduct(digits);
    return 1 + persistence(product); // we performed one transformation, now recurse
}

function getDigits(num) {
    return num.toString().split('').map(Number); // convert chars to numbers
}

function getProduct(nums) {
    return nums.reduce(function (a, b) { // nice way to get 1 result from array
        return a * b;
    }, 1);
}

console.log(persistence(39));

【讨论】:

    【解决方案2】:

    从一个函数开始,如果满足您的条件(只剩下一位数),则该函数返回结果。如果没有,则返回下一次迭代的结果,传入您要跟踪的状态(当前计数)。也许是这样的:

    function persistence(num, opt_count) {
      num = parseInt(num, 10); // Assume we're dealing with only ints.
      var count = opt_count || 0; // Count is optional, so make sure we init.
    
      if (num > 9) {
        var digits = String(num).split(''); // Split our number as string.
        num = digits.shift();
        do {
          num *= digits.shift(); // Note, multiplication will cast back automatically.
        } while(digits.length);
        count++; // Increment our count
      }
    
      if (num < 10) return count; // Return our count if we're under 10.
      return persistence(num, count); // Recurse with our current state.
    }
    
    console.log('39:  ' + persistence(39));     // 3
    console.log('999: ' + persistence(999));    // 4
    console.log('4:   ' + persistence(4));      // 0

    【讨论】:

    • 做 { num *= digits.shift(); } 而(数字。长度);计数++;伟大的实施!我应该考虑到!它是某种可以在其他情况下使用的编程模式吗?
    【解决方案3】:

    您的代码中有几个问题:

    function persistence(num) {
        var total = 1;
        var step = 0;
        // This will return a number
        var number = multiple(num);
    
        while (step < 3) {
            // Here number is a number, which doesn't have a length property so
            // the loop never runs. However, once you fix that...
            for (var i = 0; i < number.length; i++) {
    
                // splitNumbers is in the multiple function, you can't access it
                // from this function
                total *= splitNumbers[i];
            }
            multiple(number);
            step += 1;
        }
        // The function doesn't have a return statement, so even if it works,
        // it returns undefined
    }
    
    function multiple(num) {
        var splitNumbers = num.toString().split('');
        var a = splitNumbers[0];
        var b = splitNumbers[1];
        return a * b;
    }
    
    console.log(persistence(39));

    所以修复你的代码:

    function persistence(num) {
      var total = 1;
      var step = 0;
      var number = multiple(num);
      // Make splitNumbers available locally
      var splitNumbers = String(number).split('');
    
      while (step < 3) {
        // Use the length of splitNumbers, not number
        for (var i = 0; i < splitNumbers.length; i++) {
          total *= splitNumbers[i];
        }
        multiple(number);
        step += 1;
      }
      // Return the accumulated step count
      return step;
    }
    
    function multiple(num) {
      var splitNumbers = num.toString().split('');
      var a = splitNumbers[0];
      var b = splitNumbers[1];
      return a * b;
    }
    
    console.log(persistence(39));

    但这不是使用递归,您使用的是顺序编程,它比递归运行得更快(尽管不一定明显),但通常需要更多代码。

    其他答案显示了一些不错的替代解决方案,这是一个使用最新功能(和递归)的解决方案:

    function persistence(num, steps = 0) {
      if (num > 9) steps++;
      var total = (num || 0).toString().split('').reduce((a, b) => a * b);
      return total > 9? steps += persistence(total) : steps;
    }
    
    [39, 999, 4].forEach(function(num) {
      console.log(num + ' : ' + persistence(num));
    });

    【讨论】:

    • 感谢您的详尽解释!
    • 哦,您提供了解决方案。我尽量避免查看可行的代码。但这没关系!没关系)))
    猜你喜欢
    • 2014-02-22
    • 2020-04-22
    • 2019-09-21
    • 2018-08-08
    • 1970-01-01
    • 1970-01-01
    • 2021-09-07
    • 2015-01-21
    • 2016-04-15
    相关资源
    最近更新 更多