波非那切数列

斐波那契数列介绍及Python中五种方法斐波那契数列

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/chichu261/article/details/83589767

Q:斐波那契数列为什么那么重要,所有关于数学的书几乎都会提到?
A:因为斐波那契数列在数学和生活以及自然界中都非常有用。

在这里插入图片描述

1. 斐波那契数列 概念引入

斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”。

数学上,斐波那契数列以递归的形式进行定义:
F0=0F1=1Fn=Fn1+Fn2F0=0F1=1Fn=Fn−1+Fn−2 F_{0} = 0\\F_{1} = 1\\F_{n} = F_{n-1} + F_{n-2} F0=0F1=1Fn=Fn1+Fn2

场景

先来开看看“兔子数列”以及其他数学应用场景!!

1. 1 兔子数列

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

在这里插入图片描述

1.2 排列组合

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

更多数学方面知识,请戳:
斐波那契数列

斐波那契数列为什么那么重要,所有关于数学的书几乎都会提到?

2. 数列数学方法解答

2.1 兔子繁殖问题

斐波那契数列又因数学家列昂纳多·斐波那契以兔子繁殖为例子而引入,故又称为“兔子数列”。

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

我们不妨拿新出生的一对小兔子分析一下:

第一个月小兔子没有繁殖能力,所以还是一对

两个月后,生下一对小兔对数共有两对

三个月以后,老兔子又生下一对,因为小兔子还没有繁殖能力,所以一共是三对

------

依次类推可以列出下表:

经过月数123456789101112
幼仔对数 1 0 1 1 2 3 5 8 13 21 34 55
成兔对数 0 1 1 2 3 5 8 13 21 34 55 89  
总体对数 1 1 2 3 5 8 13 21 34 55 89 144  

幼仔对数=前月成兔对数

成兔对数=前月成兔对数+前月幼仔对数

总体对数=本月成兔对数+本月幼仔对数

可以看出幼仔对数、成兔对数、总体对数都构成了一个数列。这个数列有关十分明显的特点,那是:

前面相邻两项之和,构成了后一项。

2.2 排列组合
2.2.1 跨楼梯组合

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

这就是一个斐波那契数列:登上第一级台阶有一种登法;登上两级台阶,有两种登法;登上三级台阶,有三种登法;登上四级台阶,有五种登法……

1,2,3,5,8,13……所以,登上十级,有89种走法。

2.2.2 掷硬币不连续情形

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

答案是:
1/5)[(1+5)/2](10+2)[(15)/2](10+2)=144(1/√5)∗[(1+√5)/2](10+2)−[(1−√5)/2](10+2)=144 (1/√5)*{[(1+√5)/2]^(10+2) - [(1-√5)/2]^(10+2)}=144 1/5)[(1+5)/2](10+2)[(15)/2](10+2)=144

3. Python代码实现斐波那契数列

时间复杂度

空间复杂度

通过时间复杂度空间复杂度评判代码的执行效率。

  • 例如:从规模上来说,如果需要计算F(4)的值,需要进行9次元素操作

    设T(n)为计算n的时间复杂度,那么
    T(n)=T(n1)+T(n2)+O(1)T(n)=T(n−1)+T(n−2)+O(1) T(n) = T(n-1) + T(n-2)+O(1) T(n)=T(n1)+T(n2)+O(1)
    一般情况,可以得出:T(n)&lt;2T(n1)+O(1)T(n)&lt;2∗T(n−1)+O(1) T(n)&lt; 2* T(n-1) + O(1) T(n)<2T(n1)+O(1)

    粗略估算,Tn&lt;O2nT(n)&lt;O(2n) T(n) &lt; O(2^n) Tn<O2n),上述代码求解F(n)的计算,它的时间复杂度是$O(2^n)

3.1 python特有写法

打印正整数n之内的斐波那契数列

# Python特有, 常规写法
def fib(self, n):
	a = 0
	b = 1
	while a <= n:
		print(a, end=" ", flush=True)
		a, b = b, a + b  # python不借助变量交换两数的值

fib(100)  # 求n之内的斐波那契数列
 

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

3.2 递归

打印斐波那契数列前10位数字

# 递归
def fibonacci(i):
    num_list = [0, 1]
    if i < 2:
        return num_list[i]
    elif i >= 2:
        return (fibonacci(i - 2) + fibonacci(i - 1))


print(fibonacci(10))
 

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

3.3 类对象
# 迭代的方式
class FibIterator(object):
    """斐波那契数列迭代器"""
    def __init__(self, n):
        """
        :param n: int, 指明生成数列的前n个数
        """
        self.n = n
        # current用来保存当前生成到数列中的第几个数了
        self.current = 0
        # num1用来保存前前一个数,初始值为数列中的第一个数0
        self.num1 = 0
        # num2用来保存前一个数,初始值为数列中的第二个数1
        self.num2 = 1

    def __next__(self):
        """被next()函数调用来获取下一个数"""
        if self.current < self.n:
            num = self.num1
            self.num1, self.num2 = self.num2, self.num1+self.num2
            self.current += 1
            return num
        else:
            raise StopIteration

    def __iter__(self):
        """迭代器的__iter__返回自身即可"""
        return self


if __name__ == '__main__':
    fib = FibIterator(10)
    for num in fib:
        print(num, end=" ")
 
3.4 矩阵解决问题

从定义开始:
F0=0F1=1Fn=Fn1+Fn2F0=0F1=1Fn=Fn−1+Fn−2 F_{0} = 0\\F_{1} = 1\\F_{n} = F_{n-1} + F_{n-2} F0=0F1=1Fn=Fn1+Fn2
转化为矩阵形式
(Fn+1Fn)=(1110)(FnFn1)(Fn+1Fn)=(1110)∗(FnFn−1) \begin{pmatrix}F_{n+1}\\ F_{n} \end{pmatrix}=\begin{pmatrix}1&amp;1\\ 1&amp;0 \end{pmatrix}*\begin{pmatrix}F_{n}\\ F_{n-1} \end{pmatrix} (Fn+1Fn)=(1110)(FnFn1)
可以得出:(Fn+1Fn)(1110)(F1F0)(Fn+1Fn)(1110)(F1F0) \begin{pmatrix}F_{n+1}\\ F_{n} \end{pmatrix}\begin{pmatrix}1&amp;1\\ 1&amp;0 \end{pmatrix}\begin{pmatrix}F_{1}\\ F_{0} \end{pmatrix} (Fn+1Fn)(1110)(F1F0)
我们设定
A=(1110)A=(1110) A=\begin{pmatrix}1&amp;1\\ 1&amp;0 \end{pmatrix} A=(1110)
很显然可以变为如下:
A=(F2F1F1F0)A=(F2F1F1F0) A=\begin{pmatrix}F_{2}&amp;F_{1}\\ F_{1}&amp;F_{0} \end{pmatrix} A=(F2F1F1F0)
通过数学归纳法可以推出以下公式:
An=(Fn+1FnFnFn1)=(1110)nAn=(Fn+1FnFnFn−1)=(1110)n A^{n}=\begin{pmatrix}F_{n+1}&amp;F_{n}\\ F_{n}&amp;F_{n-1} \end{pmatrix}=\begin{pmatrix}1&amp;1\\ 1&amp;0 \end{pmatrix}^{n} An=(Fn+1FnFnFn1)=(1110)n
很显然计算F(n)的值,只需要进行矩阵的n次幂运算,取出结果矩阵第二行第一个元素值即可
O(n)O(1)时间复杂度:O(n),空间复杂度:O(1) 时间复杂度:O(n),空间复杂度:O(1) O(n)O(1)

这里可以利用快速幂运算求解,假设计算A的N次幂,二阶矩阵的乘法满足结合律

设A,B,C都是任意的二阶矩阵,则
A(BC)=(AB)CA(BC)=(AB)C A(BC)=(AB)C A(BC)=(AB)C

我们设定:m=[n2]m=[n2] m=[\frac{n}{2}] m=[2n]

  • 当n为偶数: AN=AmAmAN=Am∗Am A^{N}=A^{m}∗A^{m} AN=AmAm

  • 当n为奇数: AN=AmAmAAN=Am∗Am∗A A^{N}=A^{m}∗A^{m}∗A AN=AmAmA

    相当于A6=A3A3A7=A3A3AA6=A3∗A3,A7=A3∗A3∗A A^{6}=A^3∗A^3,A^7=A^3∗A^3∗A A6=A3A3A7=A3A3A

这样可以减少计算次数,因为A6=AAAAAAA6=A∗A∗A∗A∗A∗A A6=A∗A∗A∗A∗A∗A A6=AAAAAA这里有5个乘,A6=AAAAAAA6=(A∗A∗A)∗(A∗A∗A) A6=(A∗A∗A)∗(A∗A∗A) A6=AAAAAA) 计算完AAAA∗A∗A A*A*A AAA 得到结果A3A3 A^3 A3,再乘以A3A3 A^3 A3 这里用了3个乘

以下是普通数据的快速幂运算,运算改为矩阵乘法,ret改为单位矩阵即可

def qpow(base, exp):
    if exp == 0:
        return 1
    ret = 1
    while exp:
        if exp & 1:
            ret = ret * base
        base = base * base
        exp >>= 1
    return ret
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3.5 矩阵再推导

我们可以设定: n=2mn=2m n=2m n=2m
那么
A2m=(F2m+1F2mF2mF2m1)=AmAmA2m=(F2m+1F2mF2mF2m−1)=Am∗Am A^{2m}=\begin{pmatrix}F_{2m+1}&amp;F_{2m}\\ F_{2m}&amp;F_{2m-1} \end{pmatrix}=A^{m}*A^{m} A2m=(F2m+1F2mF2mF2m1)=AmAm
已知
Am=(Fm+1FmFmFm1)Am=(Fm+1FmFmFm−1) A^{m}=\begin{pmatrix}F_{m+1}&amp;F_{m}\\ F_{m}&amp;F_{m-1} \end{pmatrix} Am=(Fm+1FmFmFm1)
所以:
(Fm+1FmFmFm1)(Fm+1FmFmFm1)=(F2m+1F2mF2mF2m1)(Fm+1FmFmFm−1)∗(Fm+1FmFmFm−1)=(F2m+1F2mF2mF2m−1) \begin{pmatrix}F_{m+1}&amp;F_{m}\\ F_{m}&amp;F_{m-1} \end{pmatrix}* \begin{pmatrix}F_{m+1}&amp;F_{m}\\ F_{m}&amp;F_{m-1} \end{pmatrix}=\begin{pmatrix}F_{2m+1}&amp;F_{2m}\\ F_{2m}&amp;F_{2m-1} \end{pmatrix} (Fm+1FmFmFm1)(Fm+1FmFmFm1)=(F2m+1F2mF2mF2m1)
计算后可以得出:
(F2m+1F2m)=(F2m+1+F2mFm(Fm+1+Fm1))(F2m+1F2m)=(Fm+12+Fm2Fm∗(Fm+1+Fm−1)) \begin{pmatrix}F_{2m+1}\\ F_{2m} \end{pmatrix}=\begin{pmatrix}F_{m+1}^{2}+F_{m}^{2}\\ F_{m}*(F_{m+1}+F_{m-1}) \end{pmatrix} (F2m+1F2m)=(Fm+12+Fm2Fm(Fm+1+Fm1))

这里需要注意一点 n 需要进行奇偶性判定:

  • 当n为奇数时:m=[n2]n=2m+1m=[n2],n=2∗m+1 m=[\frac{n}{2}],n=2*m+1 m=[2n]n=2m+1 此时,(Fn+1Fn)(F2m+2F2m+1)(Fm+1(Fm+2+Fm)F2m+1+F2m)(Fn+1Fn)(F2m+2F2m+1)(Fm+1∗(Fm+2+Fm)Fm+12+Fm2) \begin{pmatrix}F_{n+1}\\ F_{n} \end{pmatrix}\begin{pmatrix}F_{2m+2}\\ F_{2m+1} \end{pmatrix}\begin{pmatrix}F_{m+1}*(F_{m+2}+F_{m})\\ F_{m+1}^{2}+F_{m}^{2}\end{pmatrix} (Fn+1Fn)(F2m+2F2m+1)(Fm+1(Fm+2+Fm)Fm+12+Fm2)
    由于 Fm+2=Fm+1+FmFm+2=Fm+1+Fm F_{m+2}=F_{m+1}+F_{m} Fm+2=Fm+1+Fm ,因此,可以推导出
    (Fn+1Fn)=(Fm+1(Fm+1+2Fm)F2m+1+F2m)(Fn+1Fn)=(Fm+1∗(Fm+1+2∗Fm)Fm+12+Fm2) \begin{pmatrix}F_{n+1}\\ F_{n} \end{pmatrix}=\begin{pmatrix}F_{m+1}*(F_{m+1}+2*F_{m})\\ F_{m+1}^{2}+F_{m}^{2}\end{pmatrix} (Fn+1Fn)=(Fm+1(Fm+1+2Fm)Fm+12+Fm2)
  • 当n为偶数时:m=n2n=2mm=n2,n=2∗m m=\frac{n}{2},n=2*m m=2nn=2m,此时
    (Fn+1Fn)=(F2m+1F2m)=(F2m+1+F2mFm(Fm+1+Fm1))(Fn+1Fn)=(F2m+1F2m)=(Fm+12+Fm2Fm∗(Fm+1+Fm−1)) \begin{pmatrix}F_{n+1}\\ F_{n} \end{pmatrix}=\begin{pmatrix}F_{2m+1}\\ F_{2m} \end{pmatrix}=\begin{pmatrix}F_{m+1}^{2}+F_{m}^{2}\\ F_{m}*(F_{m+1}+F_{m-1}) \end{pmatrix} (Fn+1Fn)=(F2m+1F2m)=(Fm+12+Fm2Fm(Fm+1+Fm1))
    由于 Fm+2=Fm+1+FmFm+2=Fm+1+Fm F_{m+2}=F_{m+1}+F_{m} Fm+2=Fm+1+Fm,因此,可以推导出:
    (Fn+1Fn)=(F2m+1+F2mFm(2Fm+1Fm))(Fn+1Fn)=(Fm+12+Fm2Fm∗(2∗Fm+1−Fm)) \begin{pmatrix}F_{n+1}\\ F_{n} \end{pmatrix}=\begin{pmatrix}F_{m+1}^{2}+F_{m}^{2}\\ F_{m}*(2*F_{m+1}-F_{m})\end{pmatrix} (Fn+1Fn)=(Fm+12+Fm2Fm(2Fm+1Fm))

所以计算F(N)的值,只需要知道F(n/2+1)和F(n/2)即可

def fib(n):
    if n < 1:
        return (1, 0)

    f_m_1, f_m = fib(n >> 1)
    if n & 1:
        return f_m_1 * (f_m_1 + 2 * f_m), f_m ** 2 + f_m_1 ** 2
    else:
        return f_m_1 ** 2 + f_m ** 2, f_m * (2 * f_m_1 - f_m)
 

 

O(log2n)O(1)时间复杂度:O(log⁡2n),空间复杂度:O(1) 时间复杂度:O(\log_2 n),空间复杂度:O(1) O(log2n)O(1)

posted @ 2019-12-06 17:10  星空之主  阅读(868)  评论(0编辑  收藏  举报