写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入:n = 2
输出:1
示例 2:
输入:n = 5
输出:5
提示:
0 <= n <= 100
我能想到的就是递归...但是普通的递归太耗时了,画一棵递归树就知道了,有太多重复的计算
那么可以使用带备忘录的递归法,也就是把算完的值存在备忘录里,需要时拿出来,这种方法大大减小了计算量,可以通过。
突然想起来算法课上讲过....学的东西全还给老师了。记得老师讲这种方法是自顶向下的
那么动态规划法就是自底向上的,从一个个小问题入手,最后解决整个大问题
动态规划
斐波那契的递推关系如下:
F(n)=F(n−1)+F(n−2)
那么可以用滚动数组法,可以节省空间
class Solution {
public int fib(int n) {
if(n<2)
return n;
int a=0,b=0,sum=1;
for(int i=2;i<=n;i++){
a=b;
b=sum;
sum=(a+b)%1000000007;
}
return sum;
}
}
这一块儿就是要注意别忘了0和1的情况,以及循环算多少次,a,b,sum的初值各自是多少。
时间复杂度:O(n)
空间复杂度:O(1) 常数级
这个效率居然还挺高的

矩阵快速幂
这种方法可以降低时间复杂度
本来不想看这个方法,结果评论区大佬说字节面试要求写出这种方法。。。真就面试造火箭吗
思路如下:(我自己是绝对想不到这种方法的。。)

注意求F(n+1)时是M连乘n次,那么求F(n)时就应该连乘n-1次
什么是快速幂算法?
简单说就是增大底数以减小指数,从而减小循环运算的次数

class Solution {
public int fib(int n) {
if(n<2)
return n;
int[][] m={{1,1},{1,0}};
int[][] temp=pow(m,n-1);
return temp[0][0];
}
public int[][] multiply(int[][] a,int[][] b){
int c[][]=new int[2][2];
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
c[i][j]=(int) (((long) a[i][0] * b[0][j] + (long) a[i][1] * b[1][j]) % 1000000007);
}
}
return c;
}
public int[][] pow(int[][] a,int n){
//普通的幂算法,会超时的那种
// for(int i=0;0<n;i++){
// m=multiply(m,m);
// }
//快速幂
int[][] ret={{1,0},{0,1}};
while(n>0){
if((n&1)==1){
ret=multiply(ret,a);
}
n>>=1;
a=multiply(a,a);
}
return ret;
}
}
才搞懂是个什么思路...
ret是个单位矩阵,用来存放最后的结果。n是幂指数。n&1也就是判断指数n是不是奇数,如果是的话就将a的值赋给它,调用multiply是因为没有将等号运算符重载,用单位矩阵乘一下就可以啦。然后n右移一位也就是指数减半,底数变为原来的2次方,经过logn次的计算就能算出最终结果了。
时间复杂度:O(log n)
空间复杂度:O(1)
参考: