【剑指offer-C++】JZ10:斐波那契数列

【剑指offer】JZ10:斐波那契数列

题目描述

描述:大家都知道斐波那契数列,现在要求输入一个正整数 n ,请你输出斐波那契数列的第 n 项。斐波那契数列是一个满足 fib(x)={
1 x=1,2
fib(x−1)+fib(x−2) x>2
​的数列。
数据范围:1≤n≤40。
要求:空间复杂度 O(1),时间复杂度 O(n) ,本题也有时间复杂度 O(logn) 的解法。

输入:4
返回值:3
说明:根据斐波那契数列的定义可知,fib(1)=1,fib(2)=1,fib(3)=fib(3-1)+fib(3-2)=2,fib(4)=fib(4-1)+fib(4-2)=3,所以答案为3。
输入:1
返回值:1
输入:2
返回值:1

解题思路

斐波那契数列:最直观的想法是,由于fib(x)=fib(x-1)+fib(x-2),其中x>=3,当x=1或者2时,fib(x)=1,那么我们不妨令a=1,b=1,c=1,其中循环从3开始直到n,不断交替变换,使得c=a+b,a=b,b=c,如此最后c即是我们想要的结果。

int Fibonacci(int n) {
        int a=1,b=1,c=1;
        for(int i=3;i<=n;i++)
        {
            c=a+b;
            a=b;
            b=c;
        }
        return c;
    }

idea:由于题目直接给出了递推公式,那么我们也可以使用递归来做。

int Fibonacci(int n) {
        int f;
        if((n==1)||(n==2))
            return 1;
        if(n>=3)
            f=Fibonacci(n-1)+Fibonacci(n-2);
        return f;
    }

idea:既然有递推公式,也可以使用递归来做,那么必然可以使用动态规划来做,因为递归是将大问题分解为小问题,而动态规划是将小问题推导为大问题。

int Fibonacci(int n) {
        vector<int> dp(n);
        dp[0]=1;
        dp[1]=1;
        for(int i=2;i<n;i++)
            dp[i]=dp[i-1]+dp[i-2];
        return dp[n-1];
    }

数学:由于有fib(n)=fib(n-1)+fib(n-2),然后又有fib(n-1)=fib(n-2)+fib(n-3)……,该题本质上是求fib(n)对应计算了多少次的fib(1)和多少次的fib(0),那么我们可以转换为如下公式,最后结果为矩阵的n-1次方的第一行第一列的数。

typedef struct Matrix{
    int a,b,c,d; //2*2矩阵
}Matrix;

Matrix Matrix_Multiply(Matrix &x,Matrix &y) //矩阵乘法
{
    Matrix z;
    z.a=x.a*y.a+x.b*y.c;
    z.b=x.a*y.b+x.b*y.d;
    z.c=x.c*y.a+x.d*y.c;
    z.d=x.c*y.b+x.d*y.d;
    return z;
}

Matrix Matrix_Quick_Pow(Matrix &x,int n) //矩阵快速幂
{
    Matrix ans={1,0,0,1}; //初始化为单位矩阵
    while(n>0)
    {
        if(n&1) //最低位为1
            ans=Matrix_Multiply(ans, x); //将x乘入结果
        x=Matrix_Multiply(x, x); //将x乘以x为下次做准备
        n>>=1; //右移一位
    }
    return ans;
}

class Solution {
public:
    int Fibonacci(int n) {
        //最后结果为矩阵的n-1次方的第一行第一列的数
        Matrix x={1,1,1,0}; //基础矩阵
        Matrix ans=Matrix_Quick_Pow(x, n-1);
        return ans.a;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值