Brian Yang
Brian Yang
algorithm designer
Mar 6, 2020 2 min read

Fibonacci

Implement a function that returns the fibonacci number at a given index. Implement this memoized.

Solution

const fibonacci = element =>
    element < 3 ? 1 : fibonacci(element - 1) + fibonacci(element - 2);
const fibonacci = (element, cache = []) => {
    if (cache[element]) return cache[element];
    else {
        if (element < 3) return 1;
        else
            cache[element] =
                fibonacci(element - 1, cache) + fibonacci(element - 2, cache);
    }
    return cache[element];
};
const power = require('./fast_power');

/**
  * Regular fibonacci implementation following the definition:
  * Fib(0) = 0
  * Fib(1) = 1
  * Fib(n) = Fib(n-1) + Fib(n-2)
  *
  * @param Number
  * @return Number
  */
const fibExponential = n =>
  n < 2 ? n : fibExponential(n - 1) + fibExponential(n - 2);

/**
  * O(n) in time, O(1) in space and doesn't use recursion
  *
  * @param Number
  * @return Number
  */
const fibLinear = n => {
  let fibNMinus2 = 0;
  let fibNMinus1 = 1;
  let fib = n;
  for (let i = 1; i < n; i++) {
    fib = fibNMinus1 + fibNMinus2;
    fibNMinus2 = fibNMinus1;
    fibNMinus1 = fib;
  }
  return fib;
};

/**
  * Implementation with memoization, O(n) in time, O(n) in space
  *
  * @param Number
  * @return Number
  */
const fibWithMemoization = (() => {
  const cache = [0, 1];

  const fib = n => {
    if (cache[n] === undefined) {
      cache[n] = fib(n - 1) + fib(n - 2);
    }
    return cache[n];
  };

  return fib;
})();

/**
  * Implementation using Binet's formula with the rounding trick.
  * O(1) in time, O(1) in space
  *
  * @param Number
  * @return Number
  */
const fibDirect = number => {
  const phi = (1 + Math.sqrt(5)) / 2;
  return Math.floor(Math.pow(phi, number) / Math.sqrt(5) + 0.5);
};

/**
  * Implementation based on matrix exponentiation.
  * O(log(n)) in time, O(1) in space
  *
  * @param Number
  * @return Number
  */
const fibLogarithmic = number => {
  // Transforms [f_1, f_0] to [f_2, f_1] and so on.
  const nextFib = [[1, 1], [1, 0]];

  const matrixMultiply = (a, b) => [
    [
      a[0][0] * b[0][0] + a[0][1] * b[1][0],
      a[0][0] * b[0][1] + a[0][1] * b[1][1]
    ],
    [
      a[1][0] * b[0][0] + a[1][1] * b[1][0],
      a[1][0] * b[0][1] + a[1][1] * b[1][1]
    ]
  ];

  const transform = power(nextFib, number, matrixMultiply, [[1, 0], [0, 1]]);

  // [f_n, f_{n-1}] = Transform * [f_0, f_{-1}] = Transform * [0, 1]
  // Hence the result is the first row of Transform multiplied by [0, 1],
  // which is the same as transform[0][1].
  return transform[0][1];
};
comments powered by Disqus