生成斐波那契数列

48
var x = 0;
var y = 1;
var z;

fib[0] = 0;
fib[1] = 1;

for (i = 2; i <= 10; i++) {
  alert(x + y);
  fib[i] = x + y;
  x = y;
  z = y;
}

我尝试生成一个简单的斐波那契数列,但没有输出。

请问有人能告诉我出了什么问题吗?

52个回答

0

最近我被问到了这个问题,这是我的解决方案:

function fib(n) {
  const arr = [0,1]; // the inital array, we need something to sum at the very beginning
  for (let i = 2; i <= n; i++) { // we want the last number, so don't forget the '=' sign
    let a = arr[i-1]; // previous Number
    let b = arr[i-2]; // the one before that
    arr.push(a+b); // push the result
  }
  return arr; // if you want the n-th number, just return arr[n] or arr.length - 1
}

console.log(fib(4));


递归解决方案如下:

// NOTE: This has extremly bad performance => Exponential time complexity 2^n

function fib(n) {
  if (n < 2) {
    return n;
  }
  return fib(n-1) + fib(n-2);
}

console.log('The n-th fibonacci number: ', fib(6));
console.log('The entire fibonacci sequence: ');

// Let's see the entire fibonacci sequence
for (let i = 0; i <= 6; i++) {
   console.log(fib(i));
}


就像之前提到的那样,上述的递归解决方案对性能影响非常糟糕。幸运的是,有一个解决办法,它被称为记忆化:

// LET'S CREATE A MEMO FUNCTION 
// (and use it on the recursive **fib** function from above):

// We want to pass in a function which is going to, eventually, 
// use this utility function
function memo(fn) { 
  const cache = {}; 
  // let's make it reusable, and by that I mean, let's assume that
  // we don't know the number of arguments that will be eventually passed in 
 return function(...args) {
// if we already call this function with the same args?
// YES => return them
   if(cache[args]) { 
     console.log('cached', args[0]);
     return cache[args];
   }
//    otherwise, we want to call our function 
// (the one using this 'memo' function) and pass in the arguments
// w/ the help of 'apply'
   const res = fn.apply(this, args);
   cache[args] = res; 
   // we want to store the result, so later if we'll be able to
   // return that if the args don't change
   console.log('not cached', args[0]);
   return res; // don't forget to return the result of it :)
 }
}

// Now, let's use the memoized function:
// NOTE: Remember the above function has to change in a way
// that it calls the memoized function instead of itself

function fastFib(n) {
//   SAME LOGIC AS BEFORE
  if (n<2) { 
    return n;
  }
// But, here is where the 'magic' happens
// Very important: We want to call the instantiated 'fibMemo' function 
// and NOT 'fastFib', cause then it wouldn't be so fast, right :)   
  return fibMemo(n-1) + fibMemo(n-2);
}

// DO NOT CALL IT, JUST PASS IT IN
const fibMemo = memo(fastFib); 

// HERE WE WANT TO PASS IN THE ARGUMENT
console.log(fibMemo(6));


0
您可以参考下面的简单递归函数。
function fib(n){
      if (n <= 2) return 1;
      return fib(n-1) + fib(n-2);
 }

console.log(fib(10)) //55 // Pass on any value to get fibonacci of.

复制几年前已存在的答案。 对于 fib(0)fib(1) 也是错误的。 - vsync

0

它只提供了一个近似值。如果这是目标,那么没问题,但应该说明一下。 - klutt
当我进行测试时,它在 n=76 时给出了错误的答案。 - klutt
这会返回错误的值,针对1和5进行了测试。 - Dima Shivrin

0
使用BigInt处理大数并使用lodash memoize缓存结果的解决方案。这可以显著提高性能。
const fibBigInt = (n) => {
  if (n <= BigInt(1)) {
    return n
  }
  return fibonacciBigInt(n - BigInt(1)) + fibonacciBigInt(n - BigInt(2))
}
const fibonacciBigInt = _.memoize(fibBigInt)

console.log(fibonacciBigInt(125n))

输出:59425114757512643212875125n

来源:https://github.com/bertolo1988/my-util-js-functions/blob/main/src/fibonacci/fibonacci.js


-1
var a = -1;
var b=0;
var temp =0;
var arry = [];
for(var i=1;i<100;i++){
    temp = a+b;
    a=b;
    b=temp;
    arry.push(b*-1);
}
console.log(arry);

-1
function getFibonacciNumbers(n) {    
    var sequence = [0, 1];
    if (n === 0 || n === 1) {
        return sequence[n];
    } 
    else {
        for (var i = 2; i < n; i++ ) {
            var sum = sequence[i - 1] + sequence[i - 2];
            sequence.push(sum);
        }
    return sequence;
    }
}
console.log(getFibonacciNumbers(0));
console.log(getFibonacciNumbers(1));
console.log(getFibonacciNumbers(9));

3
这不是对于“我的代码有什么问题?”这个问题的回答。这只是一些没有解释的其他代码。 - melpomene

-1

另一个解决方案可能是:

const fib = (num) => {
    if(num === 0) return 0;
    const arr=[0,1];
    let counter=2;      
    while(counter <=num){
        arr[counter]=arr[counter -1] + arr[counter -2]
        counter ++
    }
    return arr
}

该函数根据给定的限制返回斐波那契数列的数组。

fib(5) // returns [0, 1, 1, 2, 3, 5]

-1

你可以以函数式的方式使用递归并缓存结果。

const fibonacci = (n, cache = {1: 1, 2: 1}) =>
  cache[n] || (cache[n] = fibonacci(--n, cache) + fibonacci(--n, cache));
  
console.log(fibonacci(1000));
console.log(fibonacci(100));
console.log(fibonacci(10));


-1

这里有另一个使用 proper tail call 的例子。

递归内部的 fib 函数可以重复使用堆栈,因为生成下一个数字所需的所有内容(数字数组)都作为参数传入,无需评估其他表达式。

然而,ES2015 引入了尾调用优化。

另外一个缺点是它在每次迭代中获取数组长度(但仅一次),以生成下一个数字并按其索引获取数组元素(虽然比 pop 或 splice 或其他数组方法更快),但我没有对整个解决方案进行性能测试。

var fibonacci = function(len) {
  var fib = function(seq) {
    var seqLen = seq.length;
    if (seqLen === len) {
      return seq;
    } else {
      var curr = seq[seqLen - 1];
      var prev = seq[seqLen - 2];
      seq[seqLen] = curr + prev;
      return fib(seq);
    }
  }
  return len < 2 ? [0] : fib([0, 1]);
}

console.log(fibonacci(100));


-1
更好的选择是使用递归,但以下示例可以帮助您理解逻辑!
编辑:更正,递归最终会耗尽系统资源而无法实现预期结果。以下示例使用简单逻辑,可以处理得非常快...

var sequence = [0,1];
var range = 10;

for(var i = 0; i < range-2; i++){
    sequence.push(sequence[i]+sequence[i+1]);
}

console.log(sequence);


2
递归对于计算斐波那契数列来说是一个糟糕的想法。 - melpomene
你说得完全正确,这就是为什么我没有使用它!你可以测试我的解决方案,我相信它会比任何递归解决方案运行得更快。我只是提到递归可能是更好的解决方案,以便理解它的工作原理,但即使那样也可能不好,所以也许我需要改变描述... - obinoob
梅尔波门,是的我同意!不确定为什么我会这么说,哈哈,我知道递归会浪费很多资源,可能会耗尽内存等等...所以我写它时没有使用递归! - obinoob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接