zoukankan      html  css  js  c++  java
  • 魔力Python--斐波那契数列(全)

    1. 斐波那契数列应用广泛,对此数列的更好理解有助于我们算法的更进一步,并降低程序的时间复杂度,提高运行效率.

    2. 斐波那契数列的应用(4种):

      2.1 排列组合----经典例子:爬楼梯

    """
    有一段楼梯有10级台阶,规定每一步只能跨一级或两级,要登上第10级台阶有几种不同的走法?
    这就是一个斐波那契数列:登上第一级台阶有一种登法;登上两级台阶,有两种登法;登上三级台阶,有三种登法;登上四级台阶,有五种登法……
    1,2,3,5,8,13……所以,登上十级,有89种走法。
    类似的,一枚均匀的硬币掷10次,问不连续出现正面的可能情形有多少种?
    答案是(1/√5)*{[(1+√5)/2]^(10+2) - [(1-√5)/2]^(10+2)}=144种。
    求递推数列a⑴=1,a(n+1)=1+1/a(n)的通项公式
    由数学归纳法可以得到:a(n)=F(n+1)/F(n),将斐波那契数列的通项式代入,化简就得结果。
    """

      2.2 兔子数列----兔子繁殖问题

    """
    斐波那契数列又因数学家列昂纳多·斐波那契以兔子繁殖为例子而引入,故又称为“兔子数列”。
    一般而言,兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。如果所有兔子都不死,那么一年以后可以繁殖多少对兔子?
    我们不妨拿新出生的一对小兔子分析一下:
    第一个月小兔子没有繁殖能力,所以还是一对
    两个月后,生下一对小兔对数共有两对
    三个月以后,老兔子又生下一对,因为小兔子还没有繁殖能力,所以一共是三对
    
    幼仔对数=前月成兔对数
    成兔对数=前月成兔对数+前月幼仔对数
    总体对数=本月成兔对数+本月幼仔对数
    可以看出幼仔对数、成兔对数、总体对数都构成了一个数列。这个数列有关十分明显的特点,那是:前面相邻两项之和,构成了后一项。
    这个数列是意大利中世纪数学家斐波那契在<算盘全书>中提出的,这个级数的通项公式,除了具有a(n+2)=an+a(n+1)的性质外,
    还可以证明通项公式为:an=(1/√5)*{[(1+√5)/2]^n-[(1-√5)/2]^n}(n=1,2,3,...)
    """

      2.3 数列与矩阵(现在的我暂时用不上)

    """
    对于斐波那契数列1、1、2、3、5、8、13、……。有如下定义
    F(n)=F(n-1)+F(n-2)
    F(1)=1
    F(2)=1
    对于以下矩阵乘法
    F(n+1) = (1,1 ) (F(n),F(n-1))T
    F(n) =(1,0 ) (F(n),F(n-1))T
    它的运算就是右边的矩阵 (1,1)乘以矩阵(F(n),F(n-1)),右边的矩阵(1,0 ) 乘以矩阵(F(n),F(n-1)),得到:
    F(n+1)=F(n)+F(n-1)
    F(n)=F(n)
    可见该矩阵的乘法完全符合斐波那契数列的定义
    设矩阵A=第一行(1,1)第二行(1,0) 迭代n次可以得到:F(n+1) =A^(n) *( F(2),F(1))T= A^(n)*(1,1)T
    这就是斐波那契数列的矩阵乘法定义。
    另矩阵乘法的一个运算法则A^n(n为偶数) = A^(n/2)* A^(n/2),这样我们通过二分的思想,可以实现对数复杂度的矩阵相乘。
    因此可以用递归的方法求得答案。
    
    数列值的另一种求法:
    F(n) = [ (( sqrt ( 5 ) + 1 ) / 2) ^ n ]
    其中[ x ]表示取距离 x 最近的整数。
    """

      2.4 斐波那契弧线(暂时用不上)

    """
    斐波那契弧线,也称为斐波那契扇形线。第一,此趋势线以二个端点为准而画出,例如,最低点反向到最高点线上的两个点。
    然后通过第二点画出一条“无形的(看不见的)”垂直线。然后,从第一个点画出第三条趋势线:38.2%, 50%和61.8%的无形垂直线交叉。 斐波纳契弧线,是潜在的支持点和阻力点水平价格。斐波纳契弧线和斐波纳契扇形线常常在图表里同时绘画出。支持点和阻力点就是由这些线的交汇点得出。 要注意的是弧线的交叉点和价格曲线会根据图表数值范围而改变,因为弧线是圆周的一部分,它的形成总是一样的。
    """

        绘制图形如右图:

    3. 如何用代码求斐波那契数列(4种方法):

      1).递归    效率最低,时间复杂度时间复杂度O(1.618^n)

    def fib_recur(n):
      assert n >= 0, "n > 0"
      if n <= 1:
        return n
      return fib_recur(n-1) + fib_recur(n-2)
    
    for i in range(1, 20):
        print(fib_recur(i), end=' ')

        PS:递归 进阶版

          使用lru_cache可减少重复计算.

    from functools import lru_cache
    
    class Solution:
        @lru_cache(10**8)
        def climbStairs(self, n):
            """
            :type n: int
            :rtype: int
            """
    
            if n == 1:
                return 1
            elif n == 2:
                return 2
            else:
                return self.climbStairs(n - 1) + self.climbStairs(n - 2)

      2)循环    也是递推法,递增法,时间复杂度O(n)

    def fib_loop(n):
      a, b = 0, 1
      for i in range(n+1):
        a, b = b, a+b
        return a
    
    
    for i in range(20):
      print(fib_loop(i), end=' ')

      3)生成器

    def fib_loop_while(max):
        a, b = 0, 1
        while max > 0:
            a, b = b, a+b
            max -= 1
            yield a
    
    
    for i in fib_loop_while(10):
        print(i)

      4)类实现内部魔法方法

    class Fibonacci(object):
        """斐波那契数列迭代器"""
    
        def __init__(self, n):
            """
            :param n:int 指 生成数列的个数
            """
            self.n = n
            # 保存当前生成到的数据列的第几个数据,生成器中性质,记录位置,下一个位置的数据
            self.current = 0
            # 两个初始值
            self.a = 0
            self.b = 1
    
        def __next__(self):
            """当使用next()函数调用时,就会获取下一个数"""
            if self.current < self.n:
                self.a, self.b = self.b, self.a + self.b
                self.current += 1
                return self.a
            else:
                raise StopIteration
    
        def __iter__(self):
            """迭代器的__iter__ 返回自身即可"""
            return self
    
    
    if __name__ == '__main__':
        fib = Fibonacci(15)
        for num in fib:
            print(num)

      5) 矩阵 时间复杂度为 O(log n) (矩阵的话不太好理解,需要先提高数学素养)

    import numpy
    def fib_matrix(n):
        res = pow((numpy.matrix([[1, 1], [1, 0]])), n) * numpy.matrix([[1], [0]])
        return res[0][0]
    for i in range(10):
        print(int(fib_matrix(i)), end=' ')
    
    ### 2
    # 使用矩阵计算斐波那契数列
    def Fibonacci_Matrix_tool(n):
        Matrix = npmpy.matrix("1 1;1 0")
        # 返回是matrix类型
        return pow(Matrix, n)  # pow函数速度快于 使用双星好 **
    
    def Fibonacci_Matrix(n):
        result_list = []
        for i in range(0, n):
            result_list.append(numpy.array(Fibonacci_Matrix_tool(i))[0][0])
        return result_list
    # 调用
    Fibonacci_Matrix(10)

    PS:因为幂运算可以使用二分加速,所以矩阵法的时间复杂度为 O(log n)
    用科学计算包numpy来实现矩阵法 O(log n)

      6) 公式求解 时间复杂度O(1)

        首先,列出公式:

    from math import sqrt
    def fibonacci(n):
        s = int(1/sqrt(5)*(pow(((1+sqrt(5))/2),n)-pow(((1-sqrt(5))/2),n)))
        return s
    
    for i in range(10):
        print(fibonacci(i))

    转自:https://baike.baidu.com/item/斐波那契数列/99145?fr=aladdin#5

      https://blog.csdn.net/JIEJINQUANIL/article/details/52422141

      https://www.cnblogs.com/panlq/p/9307203.html

      来自LeetCode的wikizero的回答

     

  • 相关阅读:
    Java8系列之重新认识HashMap(转)
    kafka 消费者和生产者测试类
    zookeeper配置
    JNLP应用程序无法打开的解决办法
    Functional Programming 资料收集
    Python的问题解决: IOError: [Errno 32] Broken pipe
    python的subprocess的简单使用和注意事项
    Python tricks(7) -- new-style class的__slots__属性
    Python tricks(6) -- python代码执行的效率
    Python tricks(5) -- string和integer的comparison操作
  • 原文地址:https://www.cnblogs.com/smithpath/p/10704250.html
Copyright © 2011-2022 走看看