python循环矩阵实现_斐波那契数列与矩阵乘法的联系以及其python实现

 斐波那契数列    即     1、1、2、3、5、8、13、21、34、.....以此类推,在很多面试题中,面试官都会让你手写斐波那契数列的实现。对于一些有编程经验的人来说,这很容易,他们可以很快写出类似以下代码:

设 n 为  大于0的正整数,求第n个斐波那契数(1为第一个,2为第二个...8为第五个)

def feb(n):    if n == 1 or n == 2:        return n    else:        return feb(n - 1) + feb(n - 2)    #这里设数列从 1,2,3,5,8 开始

但是这里有个很严重的问题就是重复计算

 例如,在计算feb(5) 时,feb(1) 会调用多少次?feb(2)呢?

运行结果可见下图

78a56e08bbb75001766037ed90af34f2.png

可以看到 feb(2)feb(1) 被多次调用

如何能避免这个问题呢?

避免重复 的关键在于 要实现检查即将进行的计算是否已经经历过。

有同学会想到使用列表,每计算一个feb(n),就将结果存储到列表的下标n 处。

result=[1,,1,2,3,5,8.....]

feb(n)=result[n]

这看起来似乎是一个好方法,但因为斐波那契数列可以是无限长的,如果计算feb(10000)是否真的需要长度10000的列表?(况且在python中实际列表所占地址空间会大于其可见长度。)所以这种方式显然不是可取的方式。

但是在斐波那契数列数列需要经常进行运算且n较小的时候,直接采取已经定义好的列表看起来的确是个一劳永逸的方法。

但是如果面试官要求你不使用列表,即尽可能减少内存占用呢?

这里问题就可以简化为只使用两个变量。本身斐波那契数列 中 第n个就是 前两个数相加的和。

只需要一直更新   feb(n-1)   和  feb(n-2)  的值即可。

现在我们可以使用for循环来实现:

def feb(n):    if n == 1 or n == 2:        return n    else:        n1,n2=1,2        for i in range(3, n):            n1,n2=n2,n1+n2        return n1 + n2
        

这样做已经效果很好了,不需要借助数组等大存储 对象,时间复杂度也只是O(n)级别。

但是有没有更好的解法?

学习高等数学、线性代数等课程时,可能有数学老师提到过斐波那契数列的另类解法--利用矩阵求解。

数列的递推公式为:f(1)=1,f(2)=2,f(n)=f(n-1)+f(n-2)(n>=3)

   用矩阵表示为:

eabd03062005f6f2a2ea3afcf218e133.png

  进一步,可以得出直接推导公式:

6cd53396808d21f12e9436458180b62f.png

接下来,我们先思考,如何用python实现矩阵相乘?

如果接触过numpy  库的话,你也许会想到numpy中的  dot 方法

利用这个方法可以直接计算两个矩阵(列表)的乘积。但是如果让你自己去实现呢?

先提醒大家,矩阵可以相乘是有前提的

设有矩阵A*B

矩阵只有当左边矩阵A的列数等于右边矩阵B的行数时,才可以相乘。乘积结果矩阵的行数等于左边矩阵的行数,乘积矩阵的列数等于右边矩阵的列数
矩阵的乘法是左行乘右列



def matrixMul(A, B):  res = [[0] * len(B[0]) for i in range(len(A))]   #结果变量  for i in range(len(A)): #对于A的每行    for j in range(len(B[0])): #对于B的每列      for k in range(len(B)):   #对于B的每行        res[i][j] += A[i][k] * B[k][j]  return res

上面的代码是可用的,但是还有什么可以优化的地方吗?
注意到循环的层数足足三层,每一层都需要计算 len()。
所以最完美的写法是应该是先计算好长度再直接用长度值去遍历。

def matrixMul(A, B):  line_A,line_B,column_B=len(A),len(B),len(B[0])   res = [[0] * column_B for i in range(line_A)]   #结果变量  for i in range(line_A): #对于A的每行    for j in range(column_B): #对于B的每列      for k in range(line_B):   #对于B的每行        res[i][j] += A[i][k] * B[k][j]  return res

现在,我们可以用 矩阵乘法来 实现 斐波那契数列了

def matrixMul(A, B):  line_A,line_B,column_B=len(A),len(B),len(B[0])   res = [[0] * column_B for i in range(line_A)]   #结果变量  for i in range(line_A): #对于A的每行    for j in range(column_B): #对于B的每列      for k in range(line_B):   #对于B的每行        res[i][j] += A[i][k] * B[k][j]  return resdef feb(n):    if n <= 1: return max(n, 0)    res = [[1, 1], [0, 1]]      # 单位矩阵,等价于1 。如果  res 取值为[[1,0],[0,1]] 则会得1,1,2,3,5,8...这个无所谓    A = [[1, 1], [1, 0]]  # A矩阵    while n:        if n & 1: res = matrixMul(res, A)  # 如果n是奇数,或者直到n=1停止条件        A = matrixMul(A, A)  # 快速幂        n >>= 1  # 整除2,向下取整    return res[0][1]
= 1: return max(n, 0)\n    res = [[1, 1], [0, 1]]  \n    # 单位矩阵,等价于1 。如果  res 取值为[[1,0],[0,1]] 则会得1,1,2,3,5,8...这个无所谓\n    A = [[1, 1], [1, 0]]  # A矩阵\n    while n:\n        if n & 1: res = matrixMul(res, A)  # 如果n是奇数,或者直到n=1停止条件\n        A = matrixMul(A, A)  # 快速幂\n        n <<= 1  # 整除2,向下取整\n    return res[0][1]","classes":[]}"   >
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值