返回
算法每日一练:第 61 天——数的幂次快速取模法
前端
2023-12-19 23:59:48
引言
在算法竞赛和编程实践中,我们经常会遇到需要计算大整数幂次模的情况。例如,在密码学中,模运算被广泛用于密钥交换和数据加密。传统方法是直接使用循环乘法,时间复杂度为 O(n)。然而,对于大指数 n,这种方法效率低下。
快速幂取模法
快速幂取模法是一种基于二进制思想的快速算法,时间复杂度为 O(logn)。其核心思想是将指数 n 拆分为二进制位,然后使用递归分治的方法逐步计算结果。
具体步骤如下:
- 将指数 n 表示为二进制形式:n = (b[k] * 2^k) + (b[k-1] * 2^(k-1)) + ... + b[1] * 2 + b[0]
- 递归计算 N^b[k] mod P,结果记为 res
- 对于每个 b[i] = 1,将 res 更新为 res * res mod P
- 返回 res
代码实现
def fast_pow(N, M, P):
# 特判 M 为 0 的情况
if M == 0:
return 1
# 将 M 转为二进制表示
b = []
while M > 0:
b.append(M % 2)
M //= 2
# 递归计算
res = 1
for i in range(len(b) - 1, -1, -1):
res = (res * res) % P
if b[i] == 1:
res = (res * N) % P
return res
时间复杂度分析
快速幂取模法的递归层数为 O(logn),每次递归需要执行一个乘法和一个取模操作,时间复杂度为 O(1)。因此,总时间复杂度为 O(logn)。
举例
假设我们要计算 2^10000 mod 1000007。
使用快速幂取模法:
b = [0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0] # 10000 的二进制表示
res = 1
for i in range(len(b) - 1, -1, -1):
res = (res * res) % 1000007
if b[i] == 1:
res = (res * 2) % 1000007
print(res) # 输出:604661
使用循环乘法:
res = 1
for i in range(10000):
res = (res * 2) % 1000007
print(res) # 输出:604661
可以看出,快速幂取模法比循环乘法快得多,尤其当指数 n 较大时。
总结
快速幂取模法是一种高效且实用的算法,可用于快速计算大整数幂次模。该算法基于二进制思想,通过递归分治的方法大幅减少了乘法次数,时间复杂度为 O(logn)。在算法竞赛和实际编程中,快速幂取模法有着广泛的应用。