剑指 Offer 10- I. 斐波那契数列

剑指 Offer 10- I. 斐波那契数列

题目描述:

写一个函数,输入 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

解法一:打表

思路:

考虑到斐波那契数列的定义,可以设置一个数组,这个数组存放着从0到n的斐波那契数列的值,由定义可知,下标为N的位置的值由下标为N - 1 和 N - 2 两个地方的值相加得到,且已知头两个位置的值,即我们可以通过一个循环,求得所需的值

时间复杂度:O(n)

空间复杂度:O(n)

代码:

class Solution {
    static final int mod = 1000000007;
    public int fib(int n) {
        int[] ans = new int[105];
        ans[0] = 0;
        ans[1] = 1;
        for (int i = 2; i <= n; i++){
            ans[i] = (ans[i - 1] + ans[i - 2]) % mod;
        }
        return ans[n];
    }
}

解法二:递推

思路:

考虑到解法一的局限性:要设置一个数组来存放斐波那契数列的n之前的数据的值,但题目只要求我们求得下标为n的位置上的值。因此我们可以设置两个变量,进行滚动递推,可以节省许多空间

时间复杂度:O(n)

空间复杂度:O(1)

代码:

class Solution {
    static final int mod = 1000000007;
    public int fib(int n) {
        if (n <= 1) return n;
        int a = 0, b = 1;       // 赋初始值
        for (int i = 1; i < n; i++){
            int temp = b;       
            b = (a + b) % mod;      // 进行相加,所得的值赋予 b
            a = temp % mod;         // 将相加之前 b 的值赋予 a ,从而实现a与b表示的范围向前移动一步
        }
        return b;
    }
}

解法三:矩阵快速幂

思路:

本解法涉及到了两方面的知识,一方面为与线性代数有关的构造矩阵的方法,一方面为快速幂相关的知识

  • 对于构造矩阵方面的知识:

     

  • 快速幂相关知识

    由上一个知识点,我们将问题转化成了如何快速求得一个矩阵的n - 1次方的幂,这就涉及到了快速幂

     

  • 将两个知识结合起来,就可以快速求得斐波那契数列的第n项

时间复杂度:O(㏒₂n)

空间复杂度:O(1)

代码:

class Solution {
    static final int mod = 1000000007;
    public int fib(int n) {
        if (n <= 1) return n;
        int[][] matrix = new int[][]{{1, 1}, {1, 0}};   // 构建两个矩阵
        int[][] ans = new int[][]{{1}, {0}};
        int x = n - 1;
        while (x > 0){          // 快速幂
            if ((x & 1) != 0) ans = mul(matrix, ans); // 如果二进制表示下,该位为1,就加上底数的对应次方
            matrix = mul(matrix, matrix);   // 底数平方
            x >>= 1;    // 指数除2,即指向二进制表示下的下一位数
        }
        return ans[0][0] % mod;
    }
    // 定义一个矩阵相乘的函数
    int[][] mul(int[][] a, int[][] b){
        int x = a.length, y = b[0].length, z = b.length; // 一个 x*y 的矩阵和 y*z 的矩阵相乘,得到一个 x*z 的矩阵
        int[][] res = new int[x][z];
        for (int i = 0; i < x; i++){
            for (int j = 0; j < y; j++){
                for (int k = 0; k < z; k++){
                    res[i][j] += (int)((long)((long)a[i][k] * (long)b[k][j]) % mod);
                    // 由于运算过程中可能会出现超出int范围的数值,可以将其转换为long之后,经过运算和求模,再转换为int
                    // 如果觉得麻烦,就直接将数值全设置为long,在最后返回的时候,再转换为int即可
                }
            }
        }
        return res;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值