给定两个数字N和M。任务是找到第N个斐波那契数模M。
通常,让F N为第N个斐波那契数,则输出应为F N % M 。
斐波那契数列是一系列数字,每个数字都不是。是两个前面的数字的总和。它由递归关系定义:
F0 = 0
F1 = 1
Fn = Fn-1 + Fn-2
这些没有。按以下顺序排列:0、1、1、2、3、5、8、13、21、34、55,…
在这里N可以很大。
例子:
Input: N = 438, M = 900
Output: 44
Input: N = 1548276540, M = 235
Output: 185
方法:
但是,对于这样的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 N模M。
时间复杂度: O(M 2 )