📅  最后修改于: 2023-12-03 14:55:03.599000             🧑  作者: Mango
斐波那契数列是指这样一个数列:0、1、1、2、3、5、8、13、21、34、…… 在数学上,斐波那契数列以如下被以递推的方法定义:
F(0) = 0,F(1) = 1,
F(n) = F(n – 1) + F(n – 2)(n ≥ 2,n ∈ N*)。
而斐波那契模是指在求斐波那契数列中的某个数时,取模的结果。即:
F(n) % m = ?
为了方便表示,我们用 Fm(n) 表示 F(n) % m。
直接按照斐波那契数列的定义,求出数列中的每个数,然后对其取模,即可得到斐波那契模。
def fib_mod_v1(n: int, m: int) -> int:
if n < 2:
return n % m
else:
return (fib_mod_v1(n - 1, m) + fib_mod_v1(n - 2, m)) % m
但是,该方法时间复杂度非常高,无法处理较大的 n 值。
我们可以利用数学知识,推导出斐波那契模的求解公式。
由于斐波那契数列的递推公式为:F(n) = F(n – 1) + F(n – 2)
,我们可以整理出以下矩阵:
[ F(n) ] [ 1 1 ] [ F(n-1) ]
[ ] = [ ] [ ]
[ F(n-1) ] [ 1 0 ] [ F(n-2) ]
使用矩阵快速幂,可以将时间复杂度优化到 O(logn)。
from typing import List
def matrix_mul(A: List[List[int]], B: List[List[int]]) -> List[List[int]]:
"""
矩阵乘法
"""
m, n, s = len(A), len(B[0]), len(A[0])
res = [[0] * n for _ in range(m)]
for i in range(m):
for j in range(n):
for k in range(s):
res[i][j] += A[i][k] * B[k][j]
res[i][j] %= mod
return res
def matrix_pow(A: List[List[int]], n: int) -> List[List[int]]:
"""
矩阵快速幂
"""
res = [[1, 0], [0, 1]]
while n:
if n & 1:
res = matrix_mul(res, A)
A = matrix_mul(A, A)
n >>= 1
return res
def fib_mod_v2(n: int, m: int) -> int:
if n < 2:
return n % m
else:
# 矩阵快速幂
A = [[1, 1], [1, 0]]
A_pow = matrix_pow(A, n - 1)
return A_pow[0][0] % m
根据鸽笼原理,当 m 足够大时,必定会出现两个相邻的数 F(i) 和 F(i+1) 他们在模 m 意义下相等,即:F(i) % m == F(i+1) % m。
因此当我们计算 F(n) % m 时,我们可以计算出所有小于 m² 的 F(i) % m 的值,找到其中连续相等的数对 F(i) 和 F(i+1),即可计算出 F(n) % m。
def fib_mod_v3(n: int, m: int) -> int:
if n < 2:
return n % m
else:
# 计算所有小于 m² 的斐波那契数对 m 取模的余数
fib_mod_list = [0, 1]
while True:
fib_mod_list.append((fib_mod_list[-1] + fib_mod_list[-2]) % m)
if fib_mod_list[-2:] == [0, 1]:
fib_mod_list.pop()
break
i = n % len(fib_mod_list)
return fib_mod_list[i]
以上为斐波那契模的几种解法。具体使用哪种方法,需要根据数据量大小和时间限制等因素进行选择。