剑指offer第十题——斐波那契数列Python多方法求解

剑指offer——斐波那契数列 python 求解,使用数学原理再次降低时间复杂度

一、题目描述

写一个函数,输入n,求斐波那契数列的前n项

二、解题方法

(1)常规递归方法实现:

解题思路:因为每当求解f(n)的时候,我们需要知道f(n-1)和f(n-2),而在获取f(n-1)的时候,我们也需要获得f(n-2)和f(n-3)……如此以来,求解问题的步骤是不断地往下找构成此问题的子问题,而子问题又与上层问题性质相同。这个时候就可以使用递归的思想求解。

方法优缺点:代码简单,容易看懂。然而思考下面这个问题:当随着n的增加,这样的递归产生了多少的计算操作呢?

  • 求解f(1)时,直接返回,计算量记为1
  • 求解f(2)时,直接返回,计算量记为1
  • 求解f(3)时,f(3)产生了f(2)和f(1)两个子问题,计算量我们记为3
    在这里插入图片描述
  • 求解f(4)的时候,f(4)产生了f(3)和f(2),此时f(3)继续递归求解,f(3)又产生了f(2)和f(1)两个子问题(整个过程计算了两次f(2),这也是为什么这个递归实现随着n的增大运行越来越慢的原因所在),此时计算总量为5
    在这里插入图片描述
  • 同理,f(5)将产生总共9次的计算量
    在这里插入图片描述
    当问题从f(n-1)扩大到f(n)时,增加了f(n-2)的计算量,这样计算量是以2的幂次数增加的,按照时间复杂度的记法,这种递归求解斐波那契数列的时间复杂度为O(2n)

代码实现

def fib(n):
    if n == 1 or n == 2:
        return 1
    else:
        return fib(n-1) + fib(n-2)
        
# 输出前七项
if __name__ == '__main__':
	for _ in range(7):
    	print(fib(_+1))

代码输出

1
1
2
3
5
8
13

(2)往后推移法

解题思路:递归法思路是从上往下,每次计算时多计算了很多重复的步骤,所以我们可以想如何去掉那些重复的步骤,这样就可以完成优化。按照斐波那契最简单的定义,f(n)=f(n-1)+f(n-2),每次记录下来f(n-1)和f(n-2),计算f(n)时只需要往后推移一次,这样就实现了不会进行重复的计算步骤了。
此时解题的关键点成了记录a和b的位置
在这里插入图片描述
在这里插入图片描述

方法优缺点:简单明了,但是每次都得从头往后移动,不能具备像生成器一样,需要的时候往后移动的特性

代码实现

def fib(n):
    if n==1 or n==2:
        return 1
    else:
        a,b = 1,1
        for i in range(n-2):
            a,b = b,a+b
        return b
        
if __name__ == '__main__':
	for _ in range(7):
    	print(fib(_+1))

(3)生成器法

解题思路:在方法(2)的基础上进行优化,插入生成器的特性,当需要用到的时候,生成下一个数

代码实现

def fib(n):
    if n==1 or n==2:
        for _ in range(n):
            yield 1
    else:
        for _ in range(2):
            yield 1
        a,b = 1,1
        for _ in range(n-2):
            a,b = b,a+b
            yield b

if __name__ == '__main__':
	for _ in fib(7):
    	print(_)

三、二分法+矩阵求解

解题思路
在这里插入图片描述
当n-1为偶数的时候,可以求右边矩阵的(n-1)/2次幂
当n-1为奇数时,可以求右边矩阵的(n-2)/2次幂
如此递归下去,由于使用了二分的思想,讲算法的时间复杂度降低到了O(log n)

代码实现

#矩阵乘法
def matrixMul(a, b):
    c = [[None, None], [None, None]]
    c[0][0] = b[0][0] * a[0][0] + b[0][1] * a[1][0]
    c[0][1] = b[0][0] * a[0][1] + b[0][1] * a[1][1]
    c[1][0] = b[1][0] * a[0][0] + b[1][1] * a[1][0]
    c[1][1] = b[1][0] * a[0][1] + b[1][1] * a[1][1]

    return c

#获取n次幂的矩阵
def getMatrix(n):
    a = [[1, 1], [1, 0]]
    if n == 1:
        return a
    if n == 2:
        return matrixMul(a, a)
    elif n % 2 == 1:  # n为奇数
        return matrixMul(matrixMul(getMatrix((n - 1) // 2), getMatrix((n - 1) // 2)), a)
    else:  # n为偶数
        return matrixMul(getMatrix(n // 2), getMatrix(n // 2))

#获取斐波那契数列
def fib(n):
    if n <= 2:
        return 1
    else:
        return getMatrix(n - 1)[0][0]


if __name__ == '__main__':
    for _ in range(9):
        print(fib(_ + 1))

嘿嘿,I am very glateful that 你看到这里了哦~下回再见ヾ(o◕∀◕)ノヾ
Thx
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值