【问题标题】:Generating Fibonacci Sequence生成斐波那契数列
【发布时间】:2011-12-18 03:47:07
【问题描述】:
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;
}

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

谁能告诉我怎么回事?

【问题讨论】:

    标签: javascript fibonacci


    【解决方案1】:

    我喜欢 在 JS 中有很多方法可以创建斐波那契数列。我将尝试复制其中的一些。目标是将序列输出到控制台(如{n: 6, fiboNum: 8}

    很好的关闭

    // The IIFE form is purposefully omitted. See below.
    
    const fiboGenClosure = () => {
      let [a, b] = [0, 1];
      let n = 0;
      return (fiboNum = a) => {
        [a, b] = [b, a + b];
        return {
          n: n++,
          fiboNum: fiboNum
        };
      };
    }
    
    // Gets the sequence until given nth number. Always returns a new copy of the main function, so it is possible to generate multiple independent sequences.
    
    const generateFiboClosure = n => {
      const newSequence = fiboGenClosure();
      for (let i = 0; i <= n; i++) {
        console.log(newSequence());
      }
    }
    
    generateFiboClosure(21);

    花式 ES6 生成器

    类似于上面的闭包模式,利用了生成器函数和for..of循环的优点。

    // The 'n' argument is a substitute for index.
    
    function* fiboGen(n = 0) {
      let [a, b] = [0, 1];
      while (true) {
        yield [a, n++];
        [a, b] = [b, a + b];
      }
    }
    
    // Also gives a new sequence every time is invoked.
    
    const generateFibonacci = n => {
      const iterator = fiboGen();
      for (let [value, index] of iterator) {
        console.log({
          n: index,
          fiboNum: value
        });
        if (index >= n) break;
      }
    }
    
    generateFibonacci(21);

    尾调用递归

    这个有点棘手,因为现在是 2018 年末,TC 优化仍然是一个问题。但老实说——如果你不使用任何聪明的技巧来让默认的 JS 引擎使用一个非常大的数字,它会变得头晕目眩,并声称下一个斐波那契数在迭代 1477 时是“无穷大”。堆栈可能会在某个地方溢出大约迭代 10 000 次(很大程度上取决于浏览器、内存等……)。可以通过 try...catch 块或检查是否达到“Infinity”来填充。

    const fibonacciRTC = (n, i = 0, a = 0, b = 1) => {
      console.log({
        n: i,
        fibonacci: a
      });
      if (n === 0) return;
      return fibonacciRTC(--n, ++i, b, a + b);
    }
    
    fibonacciRTC(21)

    如果我们去掉console.log这个东西并简单地返回一个数字,它可以写成单行:

    const fibonacciRTC2 = (n, a = 0, b = 1) => n === 0 ? a : fibonacciRTC2(n - 1, b, a + b);
    
    console.log(fibonacciRTC2(21))

    重要提示!

    当我阅读this mathIsFun article 时发现,斐波那契数列也适用于负数!我尝试在上面的递归尾调用表单中实现它:

    const fibonacciRTC3 = (n, a = 0, b = 1, sign = n >= 0 ? 1 : -1) => { 
      if (n === 0) return a * sign;
        return fibonacciRTC3(n - sign, b, a + b, sign);
    }
    
    console.log(fibonacciRTC3(8)); // 21
    console.log(fibonacciRTC3(-8)); // -21

    【讨论】:

      【解决方案2】:

      黄金比例 "phi" ^ n / sqrt(5) 对 n 的斐波那契是渐近的,如果我们将该值向上取整,我们确实得到了斐波那契值。

      function fib(n) {
          let phi = (1 + Math.sqrt(5))/2;
          let asymp = Math.pow(phi, n) / Math.sqrt(5);
      
          return Math.round(asymp);
      }
      
      fib(1000); // 4.346655768693734e+208 in just a few milliseconds
      

      与基于递归的解决方案相比,这在大数上运行得更快。

      【讨论】:

      • 酷 :) 为了提高效率,我会在函数外部预先计算 Math.sqrt(5)phi。作为参考,我在 fib(7) 之前对其进行了测试,并且运行良好。使用说明:fib(0) = 0
      • 是的,在函数外预先计算 phi 会使其更快,我只是为了演示而这样做。
      • 这是计算斐波那契值的最有效方法,但它适用于不大的值。例如,它为 fib(77) 提供了错误的值。它给出了5527939700884755,但实际上它必须是5527939700884757。
      • 相同的解决方案在此之前发布在这里显然
      【解决方案3】:

      根据Interview Cake 问题,顺序为0,1,1,2,3,5,8,13,21。如果是这种情况,则此解决方案有效且无需使用数组即可递归。

      function fibonacci(n) {
         return n < 1 ? 0
              : n <= 2 ? 1
              : fibonacci(n - 1) + fibonacci(n - 2)
      }
      
      console.log(fibonacci(4))
      

      这样想。

         fibonacci(4)   .--------> 2 + 1 = 3
            |          /               |
            '--> fibonacci(3) + fibonacci(2)
                  |    ^           
                  |    '----------- 2 = 1 + 1 <----------.
      1st step -> |                     ^                |
                  |                     |                |
                  '---->  fibonacci(2) -' + fibonacci(1)-'
      

      请注意,这个解决方案不是很有效。

      【讨论】:

      • 虽然这不能扩展
      • 这个 ascii 艺术是我见过的关于这个 +1 逻辑的最好例子
      • 迄今为止最好的例子......因为递归使用而受到喜爱!
      • 无论多么昂贵,尝试处理前 500 个值!
      • 这不是对“我的代码有什么问题?”问题的回答。这只是一些其他代码,没有任何解释。这也是最糟糕的实现之一(使用递归)。
      【解决方案4】:

      我不久前遇到的一个解决方案

      function fib(n) {
       if(n<0) throw new Error('Incorrect number in a Fibonacci sequence');
       const phi = (1 + Math.sqrt(5)) / 2;
       return Math.round(Math.pow(phi, n) / Math.sqrt(5));
      }
      

      时间 O(1)

      空间 O(1)

      参考:http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/fibFormula.html

      【讨论】:

      • 它只给出一个近似值。如果这是目标,那没关系,但应该提及。
      • 当我测试它时,它给出了 n=76 的错误答案
      【解决方案5】:

      如果您需要轻松构建斐波那契数列,可以使用array destructuring assignment 来缓解您的痛苦:

      function fibonacci(n) {
        
        let fibList = [];
        let [a, b] = [0, 1]; // array destructuring to ease your pain
      
        while (a < n) {
          fibList.push(a);
          [a, b] = [b, a + b]; // less pain, more gain
        }
        
        return fibList;
      }
      
      console.log(fibonacci(10)); // prints [0, 1, 1, 2, 3, 5, 8]

      【讨论】:

        【解决方案6】:

        斐波那契 1,000 ... 10,000 ... 100,000

        在尝试计算较大的斐波那契数时,一些答案会遇到问题。其他人正在使用 phi 来近似数字。此答案将向您展示如何计算 精确 一系列大型斐波那契数,而不会遇到 JavaScript 浮点实现设置的限制。

        下面,我们在几毫秒内生成前 1,000 个斐波那契数。以后,我们会做100,000!

        const { fromInt, toString, add } =
          Bignum
        
        const bigfib = function* (n = 0)
        {
          let a = fromInt (0)
          let b = fromInt (1)
          let _
          while (n >= 0) {
            yield toString (a)
            _ = a
            a = b
            b = add (b, _)
            n = n - 1
          }
        }
        
        console.time ('bigfib')
        const seq = Array.from (bigfib (1000))
        console.timeEnd ('bigfib')
        // 25 ms
        
        console.log (seq.length)
        // 1001
        
        console.log (seq)
        // [ 0, 1, 1, 2, 3, ... 995 more elements ]
        

        让我们看看第 1000 个斐波那契数

        console.log (seq [1000])
        // 43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875
        

        10,000

        这个解决方案可以很好地扩展。我们可以在 2 秒内计算出前 10,000 个斐波那契数。在序列中的这一点上,数字长度超过 2,000 位——远远超出了 JavaScript 浮点数的容量。尽管如此,我们的结果仍包含 精确 值而没有进行近似。

        console.time ('bigfib')
        const seq = Array.from (bigfib (10000))
        console.timeEnd ('bigfib')
        // 1877 ms
        
        console.log (seq.length)
        // 10001
        
        console.log (seq [10000] .length)
        // 2090
        
        console.log (seq [10000])
        // 3364476487 ... 2070 more digits ... 9947366875
        

        当然,所有这些魔法都发生在Bignum,我们现在将分享。要了解我们将如何设计 Bignum,请回想一下您小时候是如何使用笔和纸来添加大数的……

          1259601512351095520986368
        +   50695640938240596831104
        ---------------------------
                                  ?
        

        您从右到左添加每一列,当一列溢出到两位数时,请记住将 1 带到下一列...

                         ... <-001
          1259601512351095520986368
        +   50695640938240596831104
        ---------------------------
                          ... <-472

        在上面,我们可以看到,如果我们有两个 10 位数字,则需要大约 30 次简单的加法(每列 3 次)来计算答案。这就是我们设计Bignum 工作的方式

        const Bignum =
          { fromInt: (n = 0) =>
              n < 10
                ? [ n ]
                : [ n % 10, ...Bignum.fromInt (n / 10 >> 0) ]
                
          , fromString: (s = "0") =>
              Array.from (s, Number) .reverse ()
              
          , toString: (b) =>
              Array.from (b) .reverse () .join ('')
              
          , add: (b1, b2) =>
            {
              const len = Math.max (b1.length, b2.length)
              let answer = []
              let carry = 0
              for (let i = 0; i < len; i = i + 1) {
                const x = b1[i] || 0
                const y = b2[i] || 0
                const sum = x + y + carry
                answer.push (sum % 10)
                carry = sum / 10 >> 0
              }
              if (carry > 0) answer.push (carry)
              return answer
            }
          }
        

        我们将运行一个快速测试来验证上面的示例

        const x =
          fromString ('1259601512351095520986368')
        
        const y =
          fromString ('50695640938240596831104')
        
        console.log (toString (add (x,y)))
        // 1310297153289336117817472
        

        现在是一个完整的程序演示。展开它以在您自己的浏览器中计算精确第 10,000 个斐波那契数!注意,结果和wolfram alpha提供的答案一样

        const Bignum =
          { fromInt: (n = 0) =>
              n < 10
                ? [ n ]
                : [ n % 10, ...Bignum.fromInt (n / 10 >> 0) ]
                
          , fromString: (s = "0") =>
              Array.from (s, Number) .reverse ()
              
          , toString: (b) =>
              Array.from (b) .reverse () .join ('')
              
          , add: (b1, b2) =>
            {
              const len = Math.max (b1.length, b2.length)
              let answer = []
              let carry = 0
              for (let i = 0; i < len; i = i + 1) {
                const x = b1[i] || 0
                const y = b2[i] || 0
                const sum = x + y + carry
                answer.push (sum % 10)
                carry = sum / 10 >> 0
              }
              if (carry > 0) answer.push (carry)
              return answer
            }
          }
          
        const { fromInt, toString, add } =
          Bignum
        
        const bigfib = function* (n = 0)
        {
          let a = fromInt (0)
          let b = fromInt (1)
          let _
          while (n >= 0) {
            yield toString (a)
            _ = a
            a = b
            b = add (b, _)
            n = n - 1
          }
        }
        
        console.time ('bigfib')
        const seq = Array.from (bigfib (10000))
        console.timeEnd ('bigfib')
        // 1877 ms
           
        console.log (seq.length)
        // 10001
        
        console.log (seq [10000] .length)
        // 2090
        
        console.log (seq [10000])
        // 3364476487 ... 2070 more digits ... 9947366875

        100,000

        我只是好奇这个小脚本能走多远。似乎唯一的限制是时间和记忆。下面,我们不使用近似值计算前 100,000 个斐波那契数。序列中此时的数字长度超过 20,000 位,哇!完成需要 3.18 分钟,但结果仍然与 wolfram alpha 的答案匹配

        console.time ('bigfib')
        const seq = Array.from (bigfib (100000))
        console.timeEnd ('bigfib')
        // 191078 ms
        
        console.log (seq .length)
        // 100001
        
        console.log (seq [100000] .length)
        // 20899
        
        console.log (seq [100000])
        // 2597406934 ... 20879 more digits ... 3428746875
        

        BigInt

        JavaScript 现在原生支持 BigInt。这允许非常快速地计算大整数 -

        function* fib (n)
        { let a = 0n
          let b = 1n
          let _
          while (n >= 0) {
            yield a.toString()
            _ = a
            a = b
            b = b + _
            n = n - 1
          }
        }
        
        console.time("fib(1000)")
        const result = Array.from(fib(1000))
        console.timeEnd("fib(1000)")
        document.body.textContent = JSON.stringify(result, null, 2)
        body {
            font-family: monospace;
            white-space: pre;
        }

        【讨论】:

          【解决方案7】:
          <!DOCTYPE html>
          <html>
          <body>
          <p id="fibonacci">Fibonacci</p>
          <script>
          var fibo = fibonacci() 
          function* fibonacci() {
              var x = 1, y = 1, z = 0
              yield* [x, y];
              while(true) {
                  z = x + y, x = y, y = z;
                  yield z;
              }
          }
          setInterval(
              () => document.getElementById("fibonacci").innerHTML = fibo.next().value
          , 1000);
          </script>
          </body>
          </html>
          

          【讨论】:

            【解决方案8】:
            let maxNum = 10; // can change as per your desired length
            const fibonnaci = (terms) => {
              let series = [0, 1], a = 1, b = 0, f = 0;
              for (let i = 0; i < terms; b = a, a = f, i++) {
                f = b + a
                series.push(f)
              }
              console.log(series) // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …]
            }
            fibonnaci(maxNum)
            

            干杯!

            【讨论】:

              【解决方案9】:

              为了减少时间和优化性能,我们可以在 fibo 中使用 memoization,因为 fibo(40) 会花费太多时间来计算结果,所以要处理这种情况,memoization 就出现了。 [Memoization 基本上是用来缓存基于输入的值,简单来说我们可以说我们存储了以前值的结果。

              function fibo(n, prevValues = []) {
                if (prevValues[n] != null) {
                  return prevValues[n];
                }
                let result;
                if (n <= 2) {
                  result = 1
                } else {
                  result = fibo(n - 1, prevValues) + fibo(n - 2, prevValues);
                }
                prevValues[n] = result;
                return result;
              }
              
              console.log(fibo(41))

              【讨论】:

                【解决方案10】:

                我已经尝试过了:它可能会起作用:

                <!DOCTYPE html>
                <html lang="en">
                
                <head>
                    <meta charset="UTF-8">
                    <meta name="viewport" content="width=device-width, initial-scale=1.0">
                    <title>Fibonacci</title>
                    <style>
                        * {
                            outline: 0px;
                            margin: 0px;
                        }
                
                        input[type="number"] {
                            color: blue;
                            border: 2px solid black;
                            width: 99.58vw;
                        }
                    </style>
                </head>
                
                <body>
                    <div id="myDiv" style="color: white;background-color: blue;">Numbers Here</div>
                    <input type="number" id="input1" oninput="fibonacciProgram(this.value)" placeholder="Type Some Numbers Here">
                    <script>
                        function fibonacciProgram(numberCount) {
                            let resultElement = document.getElementById("myDiv");
                            resultElement.innerHTML = " ";
                            if (isNaN(numberCount) || numberCount <= 0) {
                                resultElement.innerHTML = "please enter a number";
                                return;
                            }
                            let firstBox = 0;
                            let secondBox = 1;
                            let swichBox;
                            let entries = [];
                            entries.push(secondBox);
                            while (numberCount > 1) {
                                swichBox = firstBox + secondBox;
                                entries.push(swichBox);
                                firstBox = secondBox;
                                secondBox = swichBox;
                                numberCount--;
                            }
                            resultElement.innerHTML = entries.join(', ');
                        }
                    </script>
                </body>
                
                </html>
                

                【讨论】:

                  【解决方案11】:
                      // using recursive approach and in one line
                      const fib = x => (x <= 1)? x : fib (x - 1) + fib(x -2);
                      fib(15); // 610
                  
                      // display the 15 first 
                      Array.from({ length: 15 }, (v, i) => fib(i)); 
                      // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]
                      
                      
                  

                      // using memoization approach
                      function fibonacci(num, memo) {
                        memo = memo || {};
                        if (memo[num]) return memo[num];
                        if (num === 0) return 0;
                        if (num === 1) return 1;
                        return memo[num] = fibonacci(num - 1, memo) + fibonacci(num - 2, memo);
                      }
                      fibonacci(15); // 610
                  
                      // display the 15 first 
                      Array.from({ length: 15 }, (v, i) => fibonacci(i));
                      // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]
                  

                  【讨论】:

                    【解决方案12】:

                    实现此目的的另一种简单方法:

                    function listFibonacci(n) {
                      // declare the array starting with the first 2 values of the fibonacci sequence
                      // starting at array index 1, and push current index + previous index to the array
                      for (var fibonacci = [0, 1], i = 1; i < n; i++) 
                        fibonacci.push(fibonacci[i] + fibonacci[i - 1])
                    
                      return fibonacci
                    }
                    
                    console.log(  listFibonacci(10)  )

                    【讨论】:

                    • 我的代码真的有问题吗?尽管只是用替代解决方案做出回应,但我和其他几个人都被否决了。如果有反对投票的理由,我希望看到一个帖子与之一起发布,因为如果它有问题,它可以作为改进答案的机会。
                    • 喜欢这个解决方案!我认为这是迄今为止最干净的
                    • 喜欢这个解决方案!我认为这是迄今为止最干净的。唯一的问题是listFibonacci(0) & listFibonacci(1)
                    【解决方案13】:

                    如果使用 ES2015

                    const fib = (n, prev = 0, current = 1) => n 
                      ? fib(--n, current, prev + current) 
                      : prev + current
                    
                    console.log( fib(10) )

                    【讨论】:

                    • 可以轻松重写为箭头函数:var fib = (n, prev = 0, current = 1) =&gt; !n ? prev + current : fib(--n, current, prev+current); 似乎显示的是第 n+3 项而不是第 n 项。将测试更改为 !(n-3) 可以解决此问题;但是,这意味着 fib(0)、fib(1) 和 fib(2) 不起作用。
                    • 为了建立准确的集合 ie 0, 1, 1, 2, 3, 5... 需要再添加一个条件``` function fib(n, prev = 0, current = 1 ) { if (n > 2) { return fib(--n, current, prev+current); } if (n === 2) { return prev + current; } 返回 n; } ```
                    【解决方案14】:

                    另一种解决方案可能是:

                    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]
                    

                    【讨论】:

                      【解决方案15】:

                      你可以参考下面的简单递归函数。

                      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) 也是错误的
                      【解决方案16】:

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

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

                      如前所述,上述递归解决方案对性能的影响非常糟糕。幸运的是,有一个解决方案,它被称为 memoization:

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

                      【讨论】:

                        【解决方案17】:

                        您从未将fib 声明为数组。使用var fib = []; 解决这个问题。

                        此外,您永远不会修改 y 变量,也不会使用它。

                        下面的代码更有意义,而且它不会创建未使用的变量:

                        var i;
                        var fib = []; // Initialize array!
                        
                        fib[0] = 0;
                        fib[1] = 1;
                        for (i = 2; i <= 10; i++) {
                          // Next fibonacci number = previous + one before previous
                          // Translated to JavaScript:
                          fib[i] = fib[i - 2] + fib[i - 1];
                          console.log(fib[i]);
                        }

                        【讨论】:

                        • 别忘了输出最初的 0 和 1,斐波那契数列的前两个数。
                        • 我会像这样改进它:var sequence = [0,1]; for(var i = 0; i
                        【解决方案18】:

                        es6 - Symbol.iterator 和生成器函数:

                        let fibonacci = {
                            *[Symbol.iterator]() {
                                let pre = 0, cur = 1
                                for (;;) {
                                    [ pre, cur ] = [ cur, pre + cur ]
                                    yield cur
                                }
                            }
                        }
                        
                        for (let n of fibonacci) {
                            if (n > 1000)
                                break
                            console.log(n)
                        }
                        

                        【讨论】:

                          【解决方案19】:
                          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);
                          

                          【讨论】:

                            【解决方案20】:

                            另一种实现,虽然递归非常快并且使用单个内联函数。它达到了 javascript 64 位数字精度限制,从第 80 个序列开始(与所有其他算法一样): 例如,如果您想要第 78 项(最后一个括号中是 78):

                            (function (n,i,p,r){p=(p||0)+r||1;i=i?i+1:1;return i<=n?arguments.callee(n,i,r,p):r}(78));
                            

                            将返回:8944394323791464

                            这一直向后兼容到 ECMASCRIPT4 - 我用 IE7 对其进行了测试,它可以工作!

                            【讨论】:

                            • this answer 展示了如何计算术语 100,000 及以上
                            【解决方案21】:

                            这是一个在使用递归时完整显示生成的斐波那契数列的函数:

                            function fibonacci (n, length) {
                                if (n < 2) {
                                    return [1];   
                                }
                                if (n < 3) {
                                    return [1, 1];
                                }
                            
                                let a = fibonacci(n - 1);
                                a.push(a[n - 2] + a[n - 3]);
                                return (a.length === length) 
                                        ? a.map(val => console.log(val)) 
                                        : a;
                            
                            };
                            

                            fibonacci(5, 5) 的输出将是:

                            1
                            1
                            2
                            3
                            5
                            

                            分配给a 的值是fibonacci 函数的返回值。在下一行,计算斐波那契数列的下一个值并将其推送到a 数组的末尾。

                            fibonacci函数的length参数用于比较a数组的序列长度,必须与n参数相同。当序列的长度与length参数匹配时,将a数组输出到控制台,否则函数返回a数组并重复。

                            【讨论】:

                              【解决方案22】:

                              您可以在这里尝试这个斐波那契解决方案

                              var a = 0;
                              console.log(a);
                              var b = 1;
                              console.log(b);
                              var c;
                              for (i = 0; i < 3; i++) {
                                c = a + b;
                                console.log(c);
                                a = b + c;
                                console.log(a);
                                b = c + a;
                                console.log(b);
                              }
                              

                              【讨论】:

                                【解决方案23】:

                                您应该首先将fib 变量声明为数组(例如var fib = []var fib = new Array()),我认为您对算法有点困惑。
                                如果使用数组存储斐波那契数列,则不需要其他辅助变量(x,y,z):

                                var fib = [0, 1];
                                for(var i=fib.length; i<10; i++) {
                                    fib[i] = fib[i-2] + fib[i-1];
                                }
                                console.log(fib); 
                                

                                Click for the demo

                                你也应该考虑递归方法(注意这是优化版本):

                                function fib(n, undefined){
                                    if(fib.cache[n] === undefined){
                                        fib.cache[n] = fib(n-1) + fib(n-2);
                                    }
                                
                                    return fib.cache[n];
                                }
                                fib.cache = [0, 1, 1];
                                

                                然后,在你调用斐波那契函数之后,你就有了fib.cache 字段中的所有序列:

                                fib(1000);
                                console.log(fib.cache);
                                

                                【讨论】:

                                  【解决方案24】:

                                  更好的选择是使用递归,但以下示例可以帮助您理解逻辑!

                                  编辑:更正,递归最终会耗尽系统的资源,而不归档预期的结果。下面这个例子使用了简单的逻辑,而且处理速度非常快……

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

                                  【讨论】:

                                  • 递归对于计算斐波那契数来说是个糟糕的主意。
                                  • 你完全正确,这就是我没有使用它的原因!你可以测试我的解决方案,我相信它会比任何递归解决方案运行得更快。我刚刚提到递归将是一个更好的解决方案,以便了解它是如何工作的,但即使这样也可能很糟糕,所以也许我需要更改描述......
                                  • melpomene 是的,我同意!不知道为什么我这么说大声笑,我知道递归会浪费很多资源,可能会耗尽内存等等......这就是为什么我没有递归地写它!
                                  【解决方案25】:
                                  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));
                                  

                                  【讨论】:

                                  • 这不是对“我的代码有什么问题?”问题的回答。这只是一些其他代码,没有任何解释。
                                  【解决方案26】:
                                  function fib(n) {
                                    if (n <= 1) {
                                      return n;
                                    } else {
                                      return fib(n - 1) + fib(n - 2);
                                    }
                                  }
                                  
                                  fib(10); // returns 55
                                  

                                  【讨论】:

                                  • 虽然这段代码 sn-p 可以解决问题,including an explanation 确实有助于提高您的帖子质量。请记住,您正在为将来的读者回答问题,而这些人可能不知道您的代码建议的原因。也请尽量不要用解释性 cmets 挤满你的代码,因为这会降低代码和解释的可读性!
                                  • 这不是对“我的代码有什么问题?”问题的回答。这只是一些其他代码,没有任何解释。这也是最糟糕的实现之一(使用递归)。
                                  【解决方案27】:

                                  斐波那契(单线)

                                  function fibonacci(n) {
                                    return (n <= 1) ? n : fibonacci(n - 1) + fibonacci(n - 2);
                                  }
                                  

                                  斐波那契(递归)

                                  function fibonacci(number) {
                                    // n <= 1
                                    if (number <= 0) {
                                      return n;
                                    } else {
                                      // f(n) = f(n-1) + f(n-2)
                                      return fibonacci(number - 1) + fibonacci(number - 2);
                                    }
                                  };
                                  
                                  console.log('f(14) = ' + fibonacci(14)); // 377

                                  斐波那契(迭代)

                                   function fibonacci(number) {
                                    // n < 2
                                    if (number <= 0) {
                                      return number ;
                                    } else {
                                      var n = 2; // n = 2
                                      var fn_1 = 0; // f(n-2), if n=2
                                      var fn_2 = 1; // f(n-1), if n=2   
                                  
                                      // n >= 2
                                      while (n <= number) {
                                        var aa = fn_2; // f(n-1)
                                        var fn = fn_1 + fn_2; // f(n)
                                  
                                        // Preparation for next loop
                                        fn_1 = aa;
                                        fn_2 = fn;
                                  
                                        n++;
                                      }
                                  
                                      return fn_2;
                                    }
                                  };
                                  
                                  console.log('f(14) = ' + fibonacci(14)); // 377

                                  斐波那契(Tail Call Optimization

                                  function fibonacci(number) {
                                    if (number <= 1) {
                                      return number;
                                    }
                                  
                                    function recursion(length, originalLength, previous, next) {
                                      if (length === originalLength)
                                        return previous + next;
                                  
                                      return recursion(length + 1, originalLength, next, previous + next);
                                    }
                                  
                                    return recursion(1, number - 1, 0, 1);
                                  }
                                  
                                  console.log(`f(14) = ${fibonacci(14)}`); // 377

                                  【讨论】:

                                  • 斐波那契的递归实现具有指数复杂性,这不应该用于计算较大的斐波那契数。
                                  【解决方案28】:

                                  不需要慢循环、生成器或递归函数(有或没有缓存)。这是一个使用Arrayreduce 的快速单行代码。

                                  ECMAScript 6:

                                  var fibonacci=(n)=>Array(n).fill().reduce((a,b,c)=>a.concat(c<2?c:a[c-1]+a[c-2]),[])
                                  

                                  ECMAScript 5:

                                  function fibonacci(n){
                                      return Array.apply(null,{length:n}).reduce(function(a,b,c){return a.concat((c<2)?c:a[c-1]+a[c-2]);},[]);
                                  }
                                  

                                  在 Chrome 59 (Windows 10) 中测试:

                                  fibonacci(10); // 0 ms -> (10) [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
                                  

                                  JavaScript 在到达 Infinity 之前最多可以处理 1476 个数字。

                                  fibonacci(1476); // 11ms -> (1476) [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...]
                                  

                                  【讨论】:

                                  • 您可能想提一下,这些算法从 80 开始达到了 64 位数字精度限制。
                                  • @DarkteK - 这是性能和代码简单性最差的之一
                                  【解决方案29】:

                                  我觉得这个简单易懂:

                                  function fibonacci(limit) {
                                      let result = [0, 1];
                                  
                                      for (var i = 2; i < limit; i++) {
                                          result[result.length] = result[result.length - 1] + result[result.length - 2];
                                      }
                                  
                                      return result;
                                  
                                  }
                                  // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
                                  console.log(fibonacci(10));
                                  

                                  【讨论】:

                                  • 来自审核队列:我可以请求您在源代码周围添加一些上下文。仅代码的答案很难理解。如果您可以在帖子中添加更多信息,这将对提问者和未来的读者都有帮助。
                                  【解决方案30】:
                                  function fibo(count) {
                                  
                                      //when count is 0, just return 
                                      if (!count) return;
                                  
                                      //Push 0 as the first element into an array
                                      var fibArr = [0];
                                  
                                      //when count is 1, just print and return
                                      if (count === 1) {
                                          console.log(fibArr);
                                          return;
                                      }
                                  
                                      //Now push 1 as the next element to the same array
                                      fibArr.push(1);
                                  
                                      //Start the iteration from 2 to the count
                                      for(var i = 2, len = count; i < len; i++) {
                                          //Addition of previous and one before previous
                                          fibArr.push(fibArr[i-1] + fibArr[i-2]);
                                      }
                                  
                                      //outputs the final fibonacci series
                                      console.log(fibArr);
                                  }
                                  

                                  无论我们需要什么计数,我们都可以将它提供给上面的 fibo 方法,让斐波那契数列达到计数。

                                  fibo(20); //output: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]
                                  

                                  【讨论】:

                                    猜你喜欢
                                    • 2015-04-25
                                    • 2017-11-13
                                    • 1970-01-01
                                    • 2012-04-26
                                    • 2011-02-20
                                    • 2013-02-24
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 2011-04-26
                                    相关资源
                                    最近更新 更多