为什么这个递归函数超出了调用堆栈的大小?

时间:2018-05-18 09:12:57

标签: recursion runtime-error division stack-size

我试图编写一个函数来查找1到20之间所有整数除以的最小数。 (让我们称之为条件D)

这是我的解决方案,它超出了调用堆栈大小限制。

function findSmallest(num){
    var count = 2
    while (count<21){
        count++
        if (num % count !== 0){
            // exit the loop
            return findSmallest(num++)
        }

    }
    return num
}

console.log(findSmallest(20))

某处我对此的推理是错误的,但是我的看法如何(请纠正我错误的地方):

使用不满足条件D的数字N调用此函数将导致使用N + 1再次调用该函数。最终,当它达到应满足条件D的数字M时,while循环运行一直通过,函数返回数字M,不再有递归调用。

但是我在运行它时遇到了这个错误:

  

function findSmallest(num){                        ^

     

RangeError:超出最大调用堆栈大小

我知道这样的错误几乎总是由于递归函数没有达到基本情况。这是问题,如果是,问题出在哪里?

2 个答案:

答案 0 :(得分:1)

我发现了两个错误。

  • 在您的while循环中,count的值为3到21。
  • num的值在循环中更改。 num++应为num + 1

但是,即使修复了这些错误,也无法解决错误。 答案是232792560。 此递归深度太大,因此堆栈内存耗尽。

例如,此代码会导致相同的错误。

function foo (num) {
    if (num === 0) return
    else foo(num - 1)
}

foo(232792560)

没有递归的编码可以避免错误。

答案 1 :(得分:1)

您的问题是您输入的递归次数超过2亿次(加上上一个答案中发现的错误)。您要查找的数字是所有素数的倍数乘以其定义范围的每个数字中的最大出现次数。所以这是你的解决方案:

function findSmallestDivisible(n) {
    if(n < 2 || n > 100) {
    throw "Numbers between 2 and 100 please";
  }
    var arr = new Array(n), res = 2;
  arr[0] = 1;
  arr[1] = 2;
  for(var i = 2; i < arr.length; i++) {
    arr[i] = fix(i, arr);
    res *= arr[i];
  }
  return res;
}

function fix(idx, arr) {
    var res = idx + 1;
  for(var i = 1; i < idx; i++) {
    if((res % arr[i]) == 0) {
        res /= arr[i];
    }
  }
  return res;
}

https://jsfiddle.net/7ewkeamL/