剑指offer 10-I斐波那契数列(矩阵快速幂、动态规划)


题目:输入 n ,求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下:F(0) = 0, F(1) = 1, F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
答案需要取模 1e9+7(1000000007)

解法一:矩阵快速幂

基本思路

斐波那契数列递推式:f(n)=f(n-1)+f(n-2)
且由矩阵乘法可推出下列公式:
[ f ( n ) f ( n − 1 ) ] = [ 1 1 1 0 ] [ f ( n − 1 ) f ( n − 2 ) ] = [ 1 1 1 0 ] [ 1 1 1 0 ] [ f ( n − 2 ) f ( n − 3 ) ] = … … = [ 1 1 1 0 ] n − 1 [ f ( 1 ) f ( 0 ) ] \begin{bmatrix} f(n)\\ f(n-1) \end{bmatrix}= \begin{bmatrix} 1&1\\ 1&0 \end{bmatrix} \begin{bmatrix} f(n-1)\\ f(n-2) \end{bmatrix}= \begin{bmatrix} 1&1\\ 1&0 \end{bmatrix} \begin{bmatrix} 1&1\\ 1&0 \end{bmatrix} \begin{bmatrix} f(n-2)\\ f(n-3) \end{bmatrix}=……= \begin{bmatrix} 1&1\\ 1&0 \end{bmatrix} ^{n-1} \begin{bmatrix} f(1)\\ f(0) \end{bmatrix} [f(n)f(n1)]=[1110][f(n1)f(n2)]=[1110][1110][f(n2)f(n3)]==[1110]n1[f(1)f(0)]

于是,只需求矩阵[1,1,1,0]的n-1次方,再计算其与[f(1),f(0)]的乘积即可。

整数快速幂的代码如下:

long long Pow(long long base, long long expo,long long mod)
{
	long long pow=1;
	while (expo) 
	{
		if (expo & 1) (pow *= base) %= mod;
		(base *= base) %= mod;
		expo >>= 1;
	}
	return pow;
}

 

复杂度

时间复杂度:O(log n)
空间复杂度:O(1)
 

具体实现
class Solution {
public:
    long long ans[2][2]; //{1,0,1,0}
    long long base[2][2]; //{1,1,1,0}
    long long f[2][1]; //{F(1),F(0)}
    long long mod;
    void matrix_mul(long long a[2][2],long long b[2][2]){  //矩阵乘法(a*=b)%=mod
        long long t00=a[0][0],t01=a[0][1],t10=a[1][0],t11=a[1][1];
        long long w00=b[0][0],w01=b[0][1],w10=b[1][0],w11=b[1][1];
        (a[0][0]=t00*w00+t01*w10)%=mod;
        (a[0][1]=t00*w01+t01*w11)%=mod;
        (a[1][0]=t10*w00+t11*w10)%=mod;
        (a[1][1]=t10*w01+t11*w11)%=mod;
    }

    void matrix_pow(int expo){ //矩阵快速幂 base的expo次方
        while(expo){
            if(expo&1) matrix_mul(ans,base); //(ans*=base)%=mod
            matrix_mul(base,base); //(base*=base)%mod
            expo>>=1;
        }
    }

    int fib(int n) { // 原理:[f(n),f(n-1)] = [1,1,1,0]的n-1次方 * [f(1),f(0)]
        ans[0][0]=1; ans[0][1]=0; ans[1][0]=0; ans[1][1]=1;
        base[0][0]=1; base[0][1]=1; base[1][0]=1; base[1][1]=0;
        f[0][0]=1; f[1][0]=0;
        mod=1000000007;
        if(n==0) return 0;
        matrix_pow(n-1);//计算base[1,1,1,0]的n-1次方
        //计算 base[1,1,1,0]的n-1次方 * [f(1),f(0)]
        (ans[0][0]=ans[0][0]*f[0][0]+ans[0][1]*f[1][0])%=mod;
        (ans[1][0]=ans[1][0]*f[0][0]+ans[1][1]*f[1][0])%=mod;
        return ans[0][0];
    }
};

 
 

解法二:动态规划

基本思路
  • 状态定义: 一维数组dp,dp[ i ]代表斐波那契数列第 i 个数字
  • 转移方程: dp[i+1] = dp[i] + dp[i-1]
  • 初始状态: dp[1] = 1, dp[0] =0
    但由于本题结果只由前两个状态决定,可以用普通变量代替一维数组,以降低空间复杂度。
复杂度

时间复杂度:O(n)
空间复杂度:O(1)
 

具体实现
class Solution {
public:
    int fib(int n) {
    	//a相当于dp[i-1],b相当于dp[i]
        long long a=0,b=1,mod=1000000007;
        if(n==0) return 0;
        for(int i=1;i<=n-1;i++){
            int temp=b;
            (b=a+b)%=mod;
            a=temp;
        }
        return b;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值