如何正确实现递归算法?

时间:2017-02-26 08:44:37

标签: javascript algorithm

我试图在codewars网站上解决这个问题。作为初学者,我遇到了实现各种编程技术的困难,缺乏基本的编程概念,如范围,提升等。无论如何,我决心解决这个问题。

说明说:

写一个函数,持久性,它接受一个正参数num并返回它的乘法持久性,这是你必须乘以num中的数字直到达到一位数的次数。

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);

3 个答案:

答案 0 :(得分:2)

奇怪的是,在第二个函数中你计算了一个产品(忽略了除前两个之外的所有数字),然后在main函数中你把它当作一个字符串(它不是'),然后开始再次乘以这些数字。这不是递归的原则:你应该只执行一次操作,然后进行递归调用。

这是一个解决方案:

&#13;
&#13;
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));
&#13;
&#13;
&#13;

答案 1 :(得分:1)

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

&#13;
&#13;
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
&#13;
&#13;
&#13;

答案 2 :(得分:1)

您的代码中存在一些问题:

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));
});