diff --git a/code_to_optimize_js/fibonacci.js b/code_to_optimize_js/fibonacci.js index b0ab2b51c..7955faa2e 100644 --- a/code_to_optimize_js/fibonacci.js +++ b/code_to_optimize_js/fibonacci.js @@ -12,7 +12,57 @@ function fibonacci(n) { if (n <= 1) { return n; } - return fibonacci(n - 1) + fibonacci(n - 2); + + // Fast doubling for integer n >= 2 gives O(log n) time. + // Iterative implementation to avoid array allocations and recursion overhead + if (Number.isInteger(n)) { + // Find the most significant bit position + let k = n; + let bitPos = 0; + while ((1 << (bitPos + 1)) <= k) { + bitPos++; + } + + // Start with F(1) = 1, F(2) = 1 + let a = 1; + let b = 1; + + // Process bits from MSB to LSB (skipping the MSB itself) + for (let i = bitPos - 1; i >= 0; i--) { + // Double: F(2k) = F(k)[2*F(k+1) - F(k)], F(2k+1) = F(k)^2 + F(k+1)^2 + const c = a * (2 * b - a); + const d = a * a + b * b; + + if ((k & (1 << i)) !== 0) { + // Bit is 1: we need F(2k+1) and F(2k+2) + a = d; + b = c + d; + } else { + // Bit is 0: we need F(2k) and F(2k+1) + a = c; + b = d; + } + } + + return a; + } + + // For non-integer n > 1, memoize the recursive definition to avoid exponential blowup. + const cache = new Map(); + function memo(x) { + if (x <= 1) { + return x; + } + const cached = cache.get(x); + if (cached !== undefined) { + return cached; + } + const res = memo(x - 1) + memo(x - 2); + cache.set(x, res); + return res; + } + + return memo(n); } /**