用于在更短的时间内找到斐波那契序列总和的最后一位数的代码

时间:2018-05-27 12:29:34

标签: python python-3.x fibonacci

我使用以下代码查找斐波那契数之和的最后一位数

#using python3
def fibonacci_sum(n):

    if n < 2: print(n)
    else:
        a, b = 0, 1
        sum=1
        for i in range(1,n):
            a, b = b, (a+b)
            sum=sum+b
    lastdigit=(sum)%10
    print(lastdigit)


n = int(input(""));
fibonacci_sum(n);

我的代码工作正常。但是对于像613455这样的更大的给定输入,它需要更多的时间。我需要一个高效的代码。任何人都可以帮助我。

2 个答案:

答案 0 :(得分:1)

仅跟踪最后一位数字

请注意,无论何时添加整数,总和的最后一位数仅取决于广告的最后一位数。这意味着我们只需要在每次迭代时保留最后一位数字。这同样适用于总和,在任何时候我们只需要保留其最后一位数。

def fibonacci_last_digit_sum(n):
    sum_, a, b = 0, 0, 1
    for _ in range(n):
        a, b = b, (a + b) % 10
        sum_ = (sum_ + b) % 10
    return sum_


print(fibonacci_last_digit_sum(613455)) # 2

以上产生循环结果

一项重大改进是认识到任何三重(a, b, sum_)都完全定义了序列中的下一个元素。但由于我们只跟踪最后一位数字,因此有限数量很多。这意味着三元组(a, b, sum_)的序列必须是循环的,它在某个时刻返回到相同的值。特别是,此周期长度的总上限为1000

这意味着我们可以通过我们代码的更新版本轻松地根据经验检查该周期的长度。

def fibonacci_last_digit_sum(n):
    sum_, a, b = 0, 0, 1
    for _ in range(n):
        a, b = b, (a + b) % 10
        sum_ = (sum_ + b) % 10
    return a, b, sum_

seen = set()

for x in range(1000):
    triple = fibonacci_last_digit_sum(x)
    if triple in seen:
        print('Back to start:', x)
        break
    seen.add(triple)

输出:

Back to start: 60

换句话说,周期长度为60

这意味着对于任何n,答案将与n % 60相同。这允许编写一个解决方案,其运行时仅取决于模运算n % 60which is O(log(n))

def fibonacci_last_digit_sum(n):
    sum_, a, b = 0, 0, 1
    for _ in range(n % 60):  # We range over n % 60 instead of n
        a, b = b, (a + b) % 10
        sum_ = (sum_ + b) % 10
    return sum_  

print(fibonacci_last_digit_sum(613455)) # 2

最后一项改进是对列表中的循环进行硬编码,因为它相对较短,并返回索引n % 60的值。

答案 1 :(得分:1)

您要求的代码返回前n个Fibonacci数之和的最后一位数。

首先要注意的是fib(1)+ fib(2)+ ... + fib(n)= fib(n + 2)-1。

这很容易证明:设S(n)是前n个斐波那契数的总和。然后S(1)= 1,S(2)= 2,并且S(n)-S(n-1)= fib(n)。结果归结为归纳。

第二,模2,斐波纳契数在长度为3的循环上重复,模5,斐波那契数在长度为20的循环上重复。See the wikipedia page on the Pisano period

这为我们提供了使用上述和Chinese Remainder Theorem

的O(1)解决方案
f2 = [0,1,1]
f5 = [0,1,1,2,3,0,3,3,1,4,0,4,4,3,2,0,2,2,4,1]

def f1(n):
    y = f5[(n+2) % 20]
    return (y-1)%10 if y%2==f2[(n+2)%3] else y+4

cases = [1, 2, 100, 12334, 1234567]

for i in cases:
    print(i, f1(i))