每日一题系列:斐波那契数列(不断更新题解)

斐波那契数列

斐波那契数列(Fibonacci sequence),又称黄金分割数列,指的是这样一个数列:

递推公式

通项公式

通项公式推导

此问题的线性递推数列属于二阶线性递推数列(n+2 -  n = 2)

由上可知,斐波那契数列递推公式的特征方程为:

解得    

则 

斐波那契数列的性质

与黄金分割的关系

有趣的是,这样一个完全是自然数的数列,通项公式却是用无理数来表达的。而且当 n 趋向于无穷大时,前一项与后一项的比值越来越逼近黄金分割 0.618(或者说后一项与前一项的比值小数部分越来越逼近 0.618)

平方与前后项关系

从第二项开始,每个偶数项的平方都比前后两项之积少 1,每个奇数项的平方都比前后两项之积多 1,也就是: 

                                             

                                              

两倍项的关系

                             

与集合子集的关系

斐波那契数列的第n+2项同时也代表了集合中所有不不包含相邻正整数的子集个数。

比如,n = 3, 第n+2项 为 5,此时 中所有不不包含相邻正整数的子集为 空集、{1}、{2}、{3}、{1,3}

项求和性质

斐波那契数列值的快速求法

                                                            

其中[x]表示取距离x最近的整数。

数学问题

1. 有一段楼梯有10 级台阶,规定每一步只能跨一级或两级,要登上第10 级台阶有几种不同的走法?

首先考虑登上第一级有一种走法({1}),登上第二级种走法({1,1},{2}),我们知道,由于最后一步同样只能跨一级或者两级,登上第三阶有两种情况,

  • 最后一步跨一级
  • 最后一步跨两级

所以它的走法数就等于两种情况相加,也就是前两级的走法数相加()。

2. 一枚均匀的硬币掷10次,问不连续出现正面的可能情形有多少种?

3. 求递推数列的通项公式?

4. 一般而言,兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。如果所有兔子都不死,那么一年以后可以繁殖多少对兔子?

和台阶问题类似,从一开始是新出生的一对小兔子,可得:

可见,从第三个月兔子具有繁殖能力开始,因为成兔对数,等于上月的成兔对数+上月的幼仔对数(是由上上月的成兔生的,经过两个月变成了成兔)。所以,当月的幼兔对数 等于 上月的成兔对数,也就等于上上月的兔子对数,再加 上月的兔子对数 就是当月的兔子对数。是符合斐波那契数列的性质的。

斐波那契数列的矩阵乘法定义

设矩阵A=第一行(1,1)第二行(1,0) 迭代n次可以得到:

                           F(n+ 1) =  (0,1)* A^(F(2),F(1))T = (0,1)* A^( n ) * (1,1)T

题目描述

递归算法和代码实现

由斐波那契数列从第三项开始,每一项等于前两项之和,可以使用递归计算给定整数的斐波那契数。

算法

C++版本:

class Solution {
public:
    int fib(int N) {
        if (N <= 1) {
            return N;
        }
        return fib(N-1) + fib(N-2);
    }
};

python版本:

class Solution:
    def fib(self, N: int) -> int:
        if N <= 1:
            return N
        return self.fib(N-1) + self.fib(N-2)

复杂度分析

时间复杂度:O(2^N)。从下面的fib(5) 的递归树容易知道,递归的层数为N,fib( )函数的调用次数 = 1 + 2 + 4 + ... + 2^( N - 2) = 2^( N - 1 ) - 1,所以是指数级别时间的。


空间复杂度:O(N)。因为在堆栈需要存储 fib(N) 的函数调用,因此需要与 N 成正比的空间大小。随着堆栈的不断增长,如果没有足够的内存则会导致 StackOverflowError。

记忆化自底向上算法和代码实现

通过迭代计算斐波那契数的子问题并存储已计算的值,通过已计算的值进行计算。减少递归带来的重复计算。

算法

  • 若N 小于等于 1,return N。
  • 初始化数组迭代 N,将计算出的答案存储在数组中。
  • 使用数组前面的两个斐波那契数(fib(0) ,fib(1))计算当前的斐波那契数。
  • 直达计算到 N,则 return 它的斐波那契数。

这个算法思路和动态规划的思路相同,因为斐波那契数列问题是典型的一维动态规划问题:

若新建长度为 n 的 dp 列表,则空间复杂度为 O(N) 。而由于 dp 列表第 i项只与第 i-1 和第 i-2项有关,只需要初始化三个整形变量,利用辅助变量使两个初始变量交替前进即可,从而将空间复杂度降至 O(1)

C++版本:

class Solution {
public:
    int fib(int N) {
        vector<int> res;
        res.push_back(0);
        res.push_back(1);

        for (int i = 1; i < N; ++i){
            res.push_back(res[i] + res[i - 1]);
        }
        return res[N];
    }
}

python 版本:

class Solution:
    def fib(self, N: int) -> int:
        temp = [0,1]
        if N >= 2:
            for i in range(2,N+1):
                temp[i%2] = temp[0] + temp[1]
        return temp[N%2]

补充:python中不存在大数越界的问题。

复杂度分析

时间复杂度:O(N)。迭代次数为N,线性时间。

空间复杂度:O(N),使用了空间大小为 N 的容器数组。或者优化为只用一个大小为2的数组(和使用三个临时变量原理一样),不断迭代替换这两个值(python版本 : 根据N%2判断输出的是cache[0]还是cache[1])。

矩阵求幂和代码实现

从之前的斐波那契数列数列求解可知斐波那契数列矩阵方程

       å¨è¿éæå¥å¾çæè¿°

算法

python 版本:

class Solution:
    def fib(self, N: int) -> int:
        if (N <= 1):
            return N
        A = [[1, 1], [1, 0]]
        self.matrix_power(A, N-1)
        return A[0][0]

    def matrix_power(self, A: list, N: int):
        if (N <= 1):
            return A
        self.matrix_power(A, N//2)
        self.multiply(A, A)
        B = [[1, 1], [1, 0]]

        if (N%2 != 0):
            self.multiply(A, B)

    def multiply(self, A: list, B: list):
        x = A[0][0] * B[0][0] + A[0][1] * B[1][0]
        y = A[0][0] * B[0][1] + A[0][1] * B[1][1]
        z = A[1][0] * B[0][0] + A[1][1] * B[1][0]
        w = A[1][0] * B[0][1] + A[1][1] * B[1][1]

        A[0][0] = x
        A[0][1] = y
        A[1][0] = z
        A[1][1] = w

C++版本可以用vector<vector<int>>来存储二维矩阵,其他思路类似。

复杂度分析

时间复杂度:O(log N)

空间复杂度:O(log N)。matrixPower 函数递归时堆栈使用的空间。

公式法和代码实现

斐波那契通项公式:

                            å¨è¿éæå¥å¾çæè¿°

算法

使用黄金分割率(通项公式)计算第 N 个斐波那契数。

C++版本:

class Solution {
    public:
       int fib(int N) {
           double goldenRatio = (sqrt(5) - 1) / 2;
           return (int)((pow((1+goldenRatio),N) -pow(-goldenRatio, N)) / sqrt(5));
    }
}

python 版本:

class Solution:
  def fib(N):
	golden_ratio = (5 ** 0.5 - 1) / 2
	return int(((1+golden_ratio)**N -(-golden_ratio)** N) / 5 ** 0.5)

复杂度分析

时间复杂度:O(1)。常数的时间复杂度,因为我们是基于斐波那契通项公式进行计算,没有使用循环或递归。

空间复杂度:O(1)。存储黄金分割率所使用的空间。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薛定谔的猫96

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值