题目链接:剑指 Offer 10- I. 斐波那契数列 - 力扣(LeetCode)
Fibonacci数列定义:
递归
核心是一个递归边界和递归体,复杂度分析可画递归树可得,时间复杂度是O(2^N),这是一个估算的上界,递归树最坏情况并不是满二叉树,数学上已经有证明出有通项公式可以表示:
而
空间复杂度和递归调用时的栈深有关是O(N),显然有很多次的重复调用:
class Solution {
public int fib(int n) {
if(n == 0 || n == 1) {
return n;
}
return fib(n - 1) + fib(n - 2);
}
}
动态规划
class Solution {
public int fib(int n) {
if(n == 0) {
return 0;
}
int[] dp = new int[n + 1];
dp[0] = 0;
dp[1] = 1;
for(int i = 2; i <= n; i++) {
dp[i] = dp[i-1] + dp[i-2];
dp[i] %= 1000000007;
}
return dp[n];
}
}
这里为啥要对1000000007(1e9+7)取模呢,因为为了防止出现溢出的问题,当然你也可以抛出一个异常,1000000007是一个足够大的质数,这意味着没有公约数。
// 使用滚动数组进行优化空间复杂度
class Solution {
public int fib(int n) {
if(n <= 1) {
return n;
}
int a = 0, b = 1, sum = 1;
for(int i = 2; i < n; i++) {
a = b;
b = sum;
sum = (a + b) % 1000000007;
}
return sum;
}
}
矩阵快速幂
矩阵性质:
快速幂:
这样就可以减少不必要的计算,比如2^10 = 2^5 * 2^5,少计算了4次。
通项公式法
这个快用之前介绍的通项公式直接可以得出答案时间和空间复杂度都是O(1)。
推导:https://www.zhihu.com/question/25217301/answer/30247743