LeetCode 斐波那契数算法题解 All In One
LeetCode 斐波那契数算法题解 All In One
-
Fibonacci Number
-
斐波那契数
The Fibonacci numbers
, commonly denoted F(n) form a sequence, called the Fibonacci sequence
, such that each number is the sum of the two preceding ones, starting from 0 and 1. That is,
斐波那契数,通常表示为 F(n) 形成一个序列,称为斐波那契数列,使得每个数都是前两个数的和,从 0 和 1 开始。也就是说,
F(0) = 0, F(1) = 1
F(n) = F(n - 1) + F(n - 2), for n > 1.
https://www.shuxuele.com/numbers/fibonacci-sequence.html
https://r-knott.surrey.ac.uk/Fibonacci/fibtable.html
最佳实践
性能优化
ES6 尾递归
调用优化 性能优化
尾调用
// ES6 尾递归调用优化 性能优化
function Fibonacci(n, n1 = 1, n2 = 1) {
if (n < 2) {
return n;
}
if (n === 2) {
// ✅ n2 ???
return n2;
}
return Fibonacci(n - 1, n2, n1 + n2);
}
// 0 <= n <= 30
function Fibonacci(n, n1 = 1, n2 = 1) {
if (n < 2) {
return n;
}
if (n === 2) {
return 1; ❌
}
return Fibonacci(n - 1, n2, n1 + n2);
}
function Fibonacci(n, n1 = 1, n2 = 1) {
if (n === 0) {
return 0;
}
if (n <= 2) {
return 1; ❌
}
return Fibonacci(n - 1, n2, n1 + n2);
}
/*
Fibonacci(0)
0
Fibonacci(1)
1
Fibonacci(2)
1
Fibonacci(3)
2
Fibonacci(5)
5
Fibonacci(30)
832040
Fibonacci(100)
354224848179262000000
*/
// ❌ Parameter cannot have question mark and initializer.ts(1015)
// function fibnacci(n: number, n1?: number = 1, n2?: number = 1): number {
// if (n < 2) {
// return n;
// }
// if (n === 2) {
// // ✅ new n2 = n1 + n2
// return n2;
// }
// return fibnacci(n - 1, n2, n1 + n2);
// }
// ES6 尾递归调用优化 性能优化
function fibnacci(n: number, n1: number = 1, n2: number = 1): number {
if (n < 2) {
return n;
}
if (n === 2) {
// ✅ new n2 = n1 + n2
return n2;
}
return fibnacci(n - 1, n2, n1 + n2);
}
"use strict";
/**
*
* @author xgqfrms
* @license MIT
* @copyright xgqfrms
* @created 2022-09-30
* @modified
*
* @description 509. Fibonacci Number
* @description 509. 斐波那契数
* @difficulty Easy
* @time_complexity O(n)
* @space_complexity O(n)
* @augments
* @example
* @link https://leetcode.com/problems/fibonacci-number/
* @link https://leetcode.cn/problems/fibonacci-number/
* @solutions
*
* @best_solutions
*
* @refs
*
*
*/
// export {};
const log = console.log;
// function fib(n: number): number {
// if(n === 0) {
// return 0;
// }
// if(n === 1 || n === 2) {
// return 1;
// }
// let n1 = 1;
// let n2 = 1;
// while (n > 2) {
// // ES6 swap
// [n1, n2] = [n2, (n1 + n2)];
// // ES5 swap
// // const temp = n1 + n2;
// // n1 = n2;
// // n2 = temp;
// n -= 1;
// }
// return n2;
// }
function fib(n: number): number {
if(n === 0) {
return 0;
}
let n1 = 1;
let n2 = 1;
// while loop
while (n > 2) {
// ES6 swap
[n1, n2] = [n2, (n1 + n2)];
n -= 1;
}
return n2;
}
// function fib(n: number): number {
// if(n === 0) {
// return 0;
// }
// let n1 = 1;
// let n2 = 1;
// // for loop
// for (let i = 2; i < n; i++) {
// // ES6 swap
// [n1, n2] = [n2, (n1 + n2)];
// }
// return n2;
// }
// 测试用例 test cases
const testCases = [
{
input: 0,
result: 0,
desc: 'value equal to 0',
},
{
input: 1,
result: 1,
desc: 'value equal to 1',
},
{
input: 2,
result: 1,
desc: 'value equal to 1',
},
{
input: 5,
result: 5,
desc: 'value equal to 5',
},
{
input: 8,
result: 21,
desc: 'value equal to 21',
},
// leetcode 509: 0 <= n <= 30
{
input: 30,
result: 832040,
desc: 'value equal to 832040',
},
{
input: 32,
result: 2178309,
desc: 'value equal to 2178309',
},
{
input: 64,
result: 10610209857723,
desc: 'value equal to 10610209857723',
},
{
input: 80,
result: 23416728348467685,
desc: 'value equal to 23416728348467685',
},
{
input: 90,
result: 2880067194370816120,
desc: 'value equal to 2880067194370816120',
},
// {
// input: 100,
// result: 354224848179261915075,
// desc: 'value equal to 354224848179261915075',
// },
];
log(`fib(80) ??? 23416728348467685 => 23416728348467684 =`, 23416728348467685 === 23416728348467684);
// fib(90) ??? 2880067194370816120 => 2880067194370816000 = true
log(`fib(90) ??? 2880067194370816120 => 2880067194370816000 =`, 2880067194370816000 === 2880067194370816120);
// fib(90) ??? 2880067194370816120 => 2880067194370816000 = true
// ❌ error TS2367: This condition will always return 'false' since the types '354224848179261900000' and '354224848179262000000' have no overlap.
// log(`fib(100) 超出最大范围了 ❌ 354224848179261915075 => 354224848179262000000 =`, 354224848179261915075 === 354224848179262000000, `❌\n`);
// fib(100) 超出最大范围了 ❌ 354224848179261915075 => 354224848179262000000 = false
// 超出最大范围了 ❌
// fib(100) => 354224848179261915075 Math (https://r-knott.surrey.ac.uk/Fibonacci/fibtable.html)
// fib(100) => 354224848179262000000 Chrome ❌
// fib(100) => 354224848179262000000 Node.js ❌
// $ npx ts-node ./509\ fibonacci-number.ts
for (const [i, testCase] of testCases.entries()) {
const result = fib(testCase.input);
// log(`test case ${i} result: `, result === testCase.result ? `✅ passed` : `❌ failed result = ${result}`, testCase.result);
log(`test case ${i} result: `, result === testCase.result ? `✅ passed fib(${testCase.input})'s =` : `❌ failed`, result);
if(testCase.input === 30) {
log(`⚠️ fib(n), n max is 30\n`);
}
}
// const testCases = [...new Uint8Array(100)].map((item, i) => ({
// input: i,
// result: fib(i),
// desc: `value equal to ${fib(i)}`,
// }));
// ...spread 突破, 2**8 = 256 的 number 最大值的大小限制 ✅
// const testCases = [...new Uint8Array(100)].map((item, i) => i + 1);
// for (const [i, testCase] of testCases.entries()) {
// const result = fib(testCase);
// log(`🚀 test case ${i} result = `, result);
// }
// export {}
/*
$ npx ts-node ./fib.ts
$ npx ts-node ./509\ fibonacci-number.ts
fib(80) ??? 23416728348467685 => 23416728348467684 = true
fib(90) ??? 2880067194370816120 => 2880067194370816000 = true
fib(100) 超出最大范围了 ❌ 354224848179261915075 => 354224848179262000000 = false ❌
test case 0 result: ✅ passed 0
test case 1 result: ✅ passed 1
test case 2 result: ✅ passed 1
test case 3 result: ✅ passed 5
test case 4 result: ✅ passed 21
test case 5 result: ✅ passed 2178309
test case 6 result: ✅ passed 10610209857723
test case 7 result: ✅ passed 23416728348467684
test case 8 result: ✅ passed 2880067194370816000
*/
"use strict";
/**
*
* @author xgqfrms
* @license MIT
* @copyright xgqfrms
* @created 2022-09-30
* @modified
*
* @description 509. Fibonacci Number
* @description 509. 斐波那契数
* @difficulty Easy
* @time_complexity O(n)
* @space_complexity O(n)
* @augments
* @example
* @link https://leetcode.com/problems/fibonacci-number/
* @link https://leetcode.cn/problems/fibonacci-number/
* @solutions
*
* @best_solutions
*
* @refs
*
*
*/
const log = console.log;
function fib(n) {
if(n === 0) {
return 0;
}
if(n === 1 || n === 2) {
return 1;
}
let n1 = 1;
let n2 = 1;
while (n > 2) {
// ES6 swap
[n1, n2] = [n2, (n1 + n2)];
// ES5 swap
// const temp = n1 + n2;
// n1 = n2;
// n2 = temp;
n -= 1;
}
return n2;
}
// 测试用例 test cases
const testCases = [
{
input: 0,
result: 0,
desc: 'value equal to 0',
},
{
input: 1,
result: 1,
desc: 'value equal to 1',
},
{
input: 2,
result: 1,
desc: 'value equal to 1',
},
{
input: 5,
result: 5,
desc: 'value equal to 5',
},
{
input: 8,
result: 21,
desc: 'value equal to 21',
},
{
input: 32,
result: 2178309,
desc: 'value equal to 2178309',
},
{
input: 64,
result: 10610209857723,
desc: 'value equal to 10610209857723',
},
{
input: 80,
result: 23416728348467685,
desc: 'value equal to 23416728348467685',
},
{
input: 90,
result: 2880067194370816120,
desc: 'value equal to 2880067194370816120',
},
// {
// input: 100,
// result: 354224848179261915075,
// desc: 'value equal to 354224848179261915075',
// },
];
log(`fib(80) ??? 23416728348467685 => 23416728348467684 =`, 23416728348467685 === 23416728348467684);
// fib(90) ??? 2880067194370816120 => 2880067194370816000 = true
log(`fib(90) ??? 2880067194370816120 => 2880067194370816000 =`, 2880067194370816000 === 2880067194370816120);
// fib(90) ??? 2880067194370816120 => 2880067194370816000 = true
log(`fib(100) 超出最大范围了 ❌ 354224848179261915075 => 354224848179262000000 =`, 354224848179261915075 === 354224848179262000000, `❌\n`);
// fib(100) 超出最大范围了 ❌ 354224848179261915075 => 354224848179262000000 = false
// 超出最大范围了 ❌
// fib(100) => 354224848179261915075 Math (https://r-knott.surrey.ac.uk/Fibonacci/fibtable.html)
// fib(100) => 354224848179262000000 Chrome ❌
// fib(100) => 354224848179262000000 Node.js ❌
// $node ./fib.js
for (const [i, testCase] of testCases.entries()) {
const result = fib(testCase.input);
// log(`test case ${i} result: `, result === testCase.result ? `✅ passed` : `❌ failed result = ${result}`, testCase.result);
log(`test case ${i} result: `, result === testCase.result ? `✅ passed` : `❌ failed`, result);
}
// const testCases = [...new Uint8Array(100)].map((item, i) => ({
// input: i,
// result: fib(i),
// desc: `value equal to ${fib(i)}`,
// }));
// ...spread 突破, 2**8 = 256 的 number 最大值的大小限制 ✅
// const testCases = [...new Uint8Array(100)].map((item, i) => i + 1);
// for (const [i, testCase] of testCases.entries()) {
// const result = fib(testCase);
// log(`🚀 test case ${i} result = `, result);
// }
// export {}
/*
$ node ./fib.js
fib(80) ??? 23416728348467685 => 23416728348467684 = true
fib(90) ??? 2880067194370816120 => 2880067194370816000 = true
fib(100) 超出最大范围了 ❌ 354224848179261915075 => 354224848179262000000 = false ❌
test case 0 result: ✅ passed 0
test case 1 result: ✅ passed 1
test case 2 result: ✅ passed 1
test case 3 result: ✅ passed 5
test case 4 result: ✅ passed 21
test case 5 result: ✅ passed 2178309
test case 6 result: ✅ passed 10610209857723
test case 7 result: ✅ passed 23416728348467684
test case 8 result: ✅ passed 2880067194370816000
*/
https://leetcode.com/problems/fibonacci-number/
https://leetcode.cn/problems/fibonacci-number/
demos
"use strict";
/**
*
* @author xgqfrms
* @license MIT
* @copyright xgqfrms
* @created 2022-06-12
* @modified
*
* @description 509. Fibonacci Number
* @description 509. 斐波那契数
* @difficulty Easy
* @complexity O(n)
* @time O(n)
* @augments
* @example
* @link https://leetcode.com/problems/fibonacci-number/
* @link https://leetcode.cn/problems/fibonacci-number/
* @solutions
* @refs
*
* @best_solutions
*
*/
const log = console.log;
/**
* @param {number} n
* @return {number}
*/
var fib = function(n) {
if(n <= 1) {
return n;
}
// 递归
return fib(n - 1) + fib(n - 2);
};
// DP 动态规划, 缓存
var fib = function(n) {
const cache = [0, 1];
function getCache(n) {
if(!cache.includes(n)) {
cache[n] = getCache(n - 1) + getCache(n - 2);
}
return cache[n];
}
return getCache(n);
};
// 性能优化, 滑动数组 ✅
var fib = function(n) {
if(n <= 1) {
return n;
}
const arr = [0, 1];
let sum;
for (let i = 2; i <= n; i++) {
// 前面两个元素的和
sum = arr[0] + arr[1];
arr[0] = arr[1];
arr[1] = sum;
}
return sum;
};
// var fib = function(n) {
// const arr = [0, 1];
// if(n <= 1) {
// return arr[n];
// }
// let sum;
// for (let i = 2; i <= n; i++) {
// // 前面两个元素的和
// sum = arr[0] + arr[1];
// arr[0] = arr[1];
// arr[1] = sum;
// }
// return sum;
// };
// 性能优化, 变量 swap
var fib = function(n) {
let first = 0;
let second = 1;
if(n <= 1) {
return n;
}
let sum;
for (let i = 2; i <= n; i++) {
// 前面两个元素的和
sum = first + second;
first = second;
second = sum;
}
return sum;
};
// 动态数组,空间换时间
const arr = [0, 1];
var fib = function(n) {
if(n <= 1) {
return n;
}
for (let i = 2; i <= n; i++) {
// 前面两个元素的和
arr[i] = arr[i - 1] + arr[i - 2];
}
return arr[i];
};
(() => {
const arr = [0, 1];
var fib = function(n) {
for (let i = 2; i <= n; i++) {
// 前面两个元素的和
arr[i] = arr[n - 1] + arr[n - 2];
}
return arr[i];
};
})();
refs
https://zzk.cnblogs.com/my/s/blogpost-p?Keywords=fib
https://www.cnblogs.com/xgqfrms/tag/fibonacci/
尾递归/尾调用
tail recursion
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions#recursion
Recursion is limited by stack size
递归受堆栈大小限制
https://developer.mozilla.org/en-US/docs/Glossary/Recursion
DP / 动态规划
https://xiaochen1024.com/series/6196129fc1553b002e57bef5/619621d3c1553b002e57bef8
©xgqfrms 2012-2020
www.cnblogs.com/xgqfrms 发布文章使用:只允许注册用户才可以访问!
原创文章,版权所有©️xgqfrms, 禁止转载 🈲️,侵权必究⚠️!
本文首发于博客园,作者:xgqfrms,原文链接:https://www.cnblogs.com/xgqfrms/p/16748194.html
未经授权禁止转载,违者必究!