Python中的斐波纳契数列求余数的8种解法和一种有限条件下的最优解

    这篇文章参考了许多资料,其中来自博客的有 《斐波那契数列的5种python解法》1,原文作者 :AI算法工程师YC,在这里简单记录一下学习过程。

    斐波纳契数列是python练习时经常遇见的一个很基础的问题,在网上也有许许多多的解法,在备战蓝桥杯的python个人赛,我也刚好遇见了有关斐波那契数列的问题,前前后后用了多种方法,才实现了通过系统100%的测试,达到时长内存的要求。

目录

  • 一、解题前提,要求和测试内容
    •     编码环境和工具
    •     它的问题和要求是这样子的
  • 二、测试方法
    • (1)递归法
    • (2)递推法
    • (3)生成器
    • (4)类实现内部方法
    • (5)矩阵快速幂
    • (6)线代法
    • (7)通项公式法
    • (8)最优解 数组解法

一、解题前提,要求和测试内容

    编码环境和工具

        环境为 python3.7.0,用的python3.7.0自带的IDLE无扩展库

    它的问题和要求是这样子的

 问题
    Fibonacci数列 斐波纳契(一种整数数列)
 资源限制
    时间限制:1.0s 内存限制:256.0MB
    python中的内置函数
 问题描述
    Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1。
    当n比较大时,Fn也非常大,现在我们想知道,Fn除以10007的余数是多少。
 输入格式
    输入包含一个整数n。
 输出格式
    输出一行,包含一个整数,表示Fn除以10007的余数。
 样例输入
    10
 样例输出
    55
 样例输入
    22
 样例输出
    7704
 数据规模与约定
    1 <= n <= 1,000,000。

我们的测试输入数据分别是

1
2
10
55
100
500
999
9999
99999
999999
共十组输入数据

二、测试方法

(1)递归法

def fib_recur(n):
    assert n >= 0, "n > 0"
    if n == 1 or n == 2:
        return 1
    else:
        return fib_recur( n - 1 ) % 10007 + fib_recur( n - 2 ) % 10007
n = eval(input())
print(fib_recur(n))

只能通过30%的测试,最大递归深度在比较中超过,产生递归错误。

(2)递推法

def Fibonacci(n):
  a,b = 0,1
  for i in range(n):
    a, b = b, a + b
  return a % 10007
n = eval(input())
print(Fibonacci(n))

在输入999999超时,不能满足比较大的项的斐波纳契数列,不过满足一般情况下,通了90%的测试。

(3)生成器

def Fibonacci(max):
    a, b = 0, 1
    while max > 0:
        a, b = b, a + b
        max -= 1
        yield a 
n = eval(input())
for i in Fibonacci(n):
    num = i % 10007

print(num)

通过80%的测试,接下来的测试都超时。

(4)类实现内部方法

class Fibonacci(object):

    def __init__(self, n):
        self.n = n
        self.current = 0
        self.a = 0
        self.b = 1

    def __next__(self):
        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):
        return self

n = eval(input())
if __name__ == '__main__':
    fib = Fibonacci(n)
    for num in fib:
        num1 = num % 10007

print(num1)

代码片长,不易理解,且只能通过80%的测试。

(5)矩阵快速幂

import numpy as np
def pow(n):
    a = np.array([[1,0],[0,1]])
    b = np.array([[1,1],[1,0]])
    n -= 1
    while(n > 0):
        if (n % 2 == 1):
            a = np.dot(b, a)
        b = np.dot(b, b)
        n >>= 1
    return a[0][0]
n = eval(input())
print(pow(n)%10007)

因为numpy不是python的内置函数,是扩展库,不能通过测试,但本身代码是可行的,可通过所有测试数据,运行速度满足1s以内。

(6)线代法

from functools import reduce
def Fibonacci(n):
     def m1(a,b):
         m=[[],[]]
         m[0].append(a[0][0]*b[0][0]+a[0][1]*b[1][0])
         m[0].append(a[0][0]*b[0][1]+a[0][1]*b[1][1])
         m[1].append(a[1][0]*b[0][0]+a[1][1]*b[1][0])
         m[1].append(a[1][0]*b[1][0]+a[1][1]*b[1][1])
         return m
     def m2(a,b):
         m=[]
         m.append(a[0][0]*b[0][0]+a[0][1]*b[1][0])
         m.append(a[1][0]*b[0][0]+a[1][1]*b[1][0])
         return m
     return m2(reduce(m1,[[[0,1],[1,1]] for i in range(n)]),[[0],[1]])[0]

n = eval(input())

print(Fibonacci(n)%10007)

方法难想到,我也看不懂,且只能通过80%的测试,不满足需求。

(7)通项公式法

n = eval(input())

num = 5 ** (1/2)
Fib_n1 = ( ( 1 + num ) / 2 )** n
Fib_n2 = ( ( 1 - num ) / 2 )** n
Fib_n =  1 / num  * ( Fib_n1 - Fib_n2 )

put_number = int(Fib_n % 10007)
print(put_number)     

只能通过40%的测试,会数据溢出,因为精度太大

(8)最优解 数组解法

n=eval(input())
a=[]
a.append(1)
a.append(1)
for i in range(2,n):
    a.append( (a[i-1]+a[i-2]) % 10007 )
print(a[n-1])  

通过100%的测试,满足要求,方法简单


  1. https://blog.csdn.net/qq_36134437/article/details/103019332 ↩︎

你可能感兴趣的:(python,python,算法)