斐波那切数列
前两位是固定的 1, 1 第三位开始,当前位是前两位相加的和
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...
面试题解:
给出第n位,问第n位的值为多少
class Solution {
/**
* 循环思想
* 传统斐波那切数列解法
* @param n 第几位
* @returns { Number } 第几位的值
*/
public static classicFib(n: number): number {
if (n <= 1) { return n; }
let a = 1, b = 1, c;
for (let i = 3; i <= n; i++) {
c = a + b;
a = b;
b = c;
}
return c;
}
/**
* 递归思想
* 利用斐波那切数列的规则,第n位的值 = 第n-1位 + 第n-2位
* @param n 第几位
*/
public static newFib(n: number): number {
if (n <= 1) { return n; }
return this.newFib(n - 1) + this.newFib(n - 2);
}
}
LeetCode算法题解
斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
给定 N,计算 F(N)。
这道题是典型的动态规划问题
- 什么是动态规划:动态规划就是 递归 + 记忆化
在递归的时候,经常会进行很多重复的计算,导致时间复杂度是指数级的。
动态规划时,在递归的时候,缓存上一些可以重复利用的值
从上图可以看出:
- 计算fb(5) 需要计算 fb(4) + fb(3)
- 计算fb(4) 需要计算 fb(3) + fb(2)
- 计算fb(3) 需要计算 fb(2) + fn(1)
- ...
中间我们重复计算了很多次fb(3) fb(2) fb(1)
计算的数越大 那么重复计算的次数也就越多, 若果把计算过的数存起来,可以节约很多计算量
class Memoize {
// 缓存已经计算的斐波那切数
private static cache: number[] = [0, 1]
/**
* 自顶向下的 动态规划 解 斐波那切数
* @param n 第几位数
*/
public static memoize(n: number) {
if (n < 1) return n;
// 如果已经缓存就取缓存
if (this.cache[n] !== undefined) return this.cache[n];
// 没有缓存就计算出来缓存进去
this.cache[n] = this.memoize(n - 1) + this.memoize(n - 2);
return this.cache[n]
}
}
动态规划
经典试题:青蛙跳台阶问题
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个n级的台阶总共有多少种跳法?
- 如果这只青蛙跳上了第N级台阶,那么最后一次跳跃之前,它一定在第 N-1 级 或者第 N-2级台阶上。
- 那么跳上第N级台阶有多少种跳法就变成了两个子问题
- 跳上第 N-1 级台阶的跳法 加上 跳上第 N-2 级的跳法
- 循环
f(n) = f(n -1) + f(n -2)
可以看出 青蛙跳台阶问题 就是一种斐波那契数列问题
// 青蛙跳台阶问题
function jump(n: number): number {
if (n <= 0) return -1;
if (n === 1) return 1;
if (n === 2) return 2;
return jump(n - 1) + jump(n - 2);
}
青蛙跳台阶的变型版
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶,或者N级台阶。求该青蛙跳上一个N级的台阶总共有多少种跳法?
- 可以从 n-1 跳到 n
- 可以从 n-2 跳到 n
- 可以从 n-3 跳到 n
- ...
- 也可以从 0 直接跳到 n
所以 fn = f(n -1) + f(n - 2).....+ f(1) + f(0)
// 青蛙跳台阶的变型版
function jump2(n: number): number {
if (n <= 0) return -1;
if (n === 1) return 1;
if (n === 2) return 2;
let result = 0;
for (let i = 1; i < n; i++) { // 跳的时候至少要跳一级台阶,所以从 1 开始
result += jump(n - i);
}
return result + 1; // 从0级直接跳到n级 所以+1
}