📜  斐波那契数模M和Pisano周期

📅  最后修改于: 2021-04-22 02:08:11             🧑  作者: Mango

给定两个数字NM。任务是找到第N个斐波那契数M。
通常,让F N为第N个斐波那契数,则输出应为F NM
斐波那契数列是一系列数字,每个数字都不是。是两个前面的数字的总和。它由递归关系定义:

F0 = 0
F1 = 1
Fn = Fn-1 + Fn-2

这些没有。按以下顺序排列:0、1、1、2、3、5、8、13、21、34、55,…
在这里N可以很大。

例子:

方法:
但是,对于这样的N值,应避免使用一种简单的递归方法来继续计算N个斐波那契数,其时间复杂度为O(2 N ) 。甚至具有N次迭代的算法循环的迭代或动态编程方法也不会节省时间。
这个问题可以用皮萨诺时期的性质来解决。
对于给定的N且M> = 2的值,用F i模M生成的序列(对于i在range(N)中)是周期性的。  

该周期始终以01开始。Pisano周期定义为该系列周期的长度。
为了进一步了解它,让我们看看当M很小时会发生什么:

i 0 1 2 3 4 5 6 7 8 9 10 11
Fi 0 1 1 2 3 5 8 13 21 34 55 89
Fi mod 2 0 1 1 0 1 1 0 1 1 0 1 1
Fi mod 3 0 1 1 2 0 2 2 1 0 1 1 2

对于M = 2,周期为011,长度为3;而对于M = 3,序列在8个数字之后重复。

例子:
因此,以F 2019 mod 5为例计算,我们将发现2019年的余数除以20(Pisano周期5为20)。 2019 mod 20是19。因此,F 2019 mod 5 = F 19 mod 5 =1。通常,此属性为true。
N除以M的Pisano周期时,我们需要找到余数。然后,针对新计算的N计算F (N)余数M。

以下是F N模M在Python:

Java
// Java program to calculate
// Fibonacci no. modulo m using
// Pisano Period
import java.io.*;
 
class GFG{
     
// Calculate and return Pisano Period
// The length of a Pisano Period for
// a given m ranges from 3 to m * m
public static long pisano(long m)
{
    long prev = 0;
    long curr = 1;
    long res = 0;
     
    for(int i = 0; i < m * m; i++)
    {
        long temp = 0;
        temp = curr;
        curr = (prev + curr) % m;
        prev = temp;
         
        if (prev == 0 && curr == 1)
            res= i + 1;
    }
    return res;
}
 
// Calculate Fn mod m
public static long fibonacciModulo(long n,
                                   long m)
{
     
    // Getting the period
    long pisanoPeriod = pisano(m);
     
    n = n % pisanoPeriod;
     
    long prev = 0;
    long curr = 1;
     
    if (n == 0)
        return 0;
    else if (n == 1)
        return 1;
     
    for(int i = 0; i < n - 1; i++)
    {
        long temp = 0;
        temp = curr;
        curr = (prev + curr) % m;
        prev = temp;
    }
    return curr % m;
}
 
// Driver Code
public static void main(String[] args)
{
    long n = 1548276540;
    long m = 235;
     
    System.out.println(fibonacciModulo(n, m));
}
}
 
// This code is contributor by Parag Pallav Singh


Python3
# Python3 program to calculate
# Fibonacci no. modulo m using
# Pisano Period
 
# Calculate and return Pisano Period
# The length of a Pisano Period for
# a given m ranges from 3 to m * m
def pisanoPeriod(m):
    previous, current = 0, 1
    for i in range(0, m * m):
        previous, current \
        = current, (previous + current) % m
         
        # A Pisano Period starts with 01
        if (previous == 0 and current == 1):
            return i + 1
 
# Calculate Fn mod m
def fibonacciModulo(n, m):
     
    # Getting the period
    pisano_period = pisanoPeriod(m)
     
    # Taking mod of N with
    # period length
    n = n % pisano_period
     
    previous, current = 0, 1
    if n==0:
        return 0
    elif n==1:
        return 1
    for i in range(n-1):
        previous, current \
        = current, previous + current
         
    return (current % m)
 
# Driver Code
if __name__ == '__main__':
    n = 1548276540
    m = 235
    print(fibonacciModulo(n, m))


输出:
185


235的Pisano周期为160。1548276540 mod 160为60。F 60 mod 235 =185。使用Pisano周期,我们现在需要计算斐波那契数。相对于原始问题中指定的相对较低的N进行迭代,然后计算F NM。
时间复杂度: O(M 2 )