使用reduce方法的斐波那契数列

Posted

技术标签:

【中文标题】使用reduce方法的斐波那契数列【英文标题】:Fibonacci sequence using reduce method 【发布时间】:2021-03-01 10:40:33 【问题描述】:

所以,我看到有人用reduce方法来计算斐波那契数列。 这是他的想法: (1,0) , (1,1) , (2,1) , (3,2) , (5,3) 对应于 1、1、2、3、5、8、13、21.......

代码看起来像这样

def fib_reduce(n):
    initial =(1,0)
    dummy = range(n)
    fib_n = reduce(lambda prev ,b : (prev[0] + prev[1], prev[0]),
                   dummy,
                   initial)
    
    return fib_n[0]

我理解(prev[0] + prev[1] , prev[0]) 就像 a, b = b, b + a。 但是,我不明白这个b 代表什么?

有人可以解释一下b吗?

【问题讨论】:

我在这里看不到任何递归。 请注意,这不是递归算法。虽然reduce 可以递归实现,但在Python 中它实际上是一个for 循环(pure Python implementation,C implementation)。 【参考方案1】:

使用reduce重复应用函数

This answer 建议编写自己的函数 repeated 以重复应用函数,而不是使用虚拟的第二个参数调用 reduce

我们仍然使用reduce,但以更实用的方式使用itertools.repeat

from itertools import repeat
from functools import reduce

def repeated(func, n):
    def apply(x, f):
        return f(x)
    def ret(x):
        return reduce(apply, repeat(func, n), x)
    return ret

def fibonacci(n):
  get_next_pair = lambda p: (sum(p), p[0])
  first_pair = (1, 0)
  return repeated(get_next_pair, n)(first_pair)[1]

print(fibonacci(0), fibonacci(1), fibonacci(11))
# 0 1 89

使用线性代数重复应用线性函数

您要应用的函数lambda a,b: b,a+b 恰好是一个线性函数。它可以用一个 2*2 的矩阵来表示。将函数重复应用于二元元组与重复将二元向量乘以矩阵相同。

这很酷,因为利用矩阵的力量比重复应用一个函数要快得多。

import numpy as np

def fibonacci(n):
  return np.linalg.matrix_power(np.array([[0, 1],[1,1]]), n).dot(np.array([0,1]))[0]

print(fibonacci(0), fibonacci(1), fibonacci(11))
# 0 1 89

如果你不喜欢单行,这里是用更明确的变量名分解成几行的同一个函数:

import numpy as np

def fibonacci(n):
  next_pair_matrix = np.array([[0, 1],[1,1]])
  matrix_to_the_nth = np.linalg.matrix_power(next_pair_matrix, n)
  first_pair_vector = np.array([0,1])
  nth_pair_vector = matrix_to_the_nth.dot(first_pair_vector)
  return nth_pair_vector[0]

print(fibonacci(0), fibonacci(1), fibonacci(11))
# 0 1 89

【讨论】:

通过运行t0 = time.perf_counter(); y = fibonacci(10000); t1 = time.perf_counter() 十次并取平均值,将我的reduce 版本与您的答案中的for-loop 版本进行比较,我得到1.56ms for-loop; 3.72ms 用于减少;和0.125ms 用于矩阵。 fibonacci(100000) 我得到:forloop 74.4ms; reduce 153.4ms;矩阵 0.14 毫秒。 哎呀,你可以忘记矩阵版本的时间。显然,for-loop 和 reduce 版本都使用 python 的大整数,但矩阵版本没有,并且为 fib(100000) 返回不正确的结果。

以上是关于使用reduce方法的斐波那契数列的主要内容,如果未能解决你的问题,请参考以下文章

斐波那契数列

斐波那契数列

P1-2017级算法第一次上机 A 水水的斐波那契数列

使用数组和 For 循环的斐波那契数列

九度oj 题目1075:斐波那契数列

介绍下斐波那契数列。