0、背景
计算形如3^100次方这种大幂运算,朴素算法要一个一个乘100多遍,时间复杂度为O(n),很低效
但如果我们换个思路,9=3^2
`3100=950=(81)^25
=(8181)^1281…
这样子的时间负责度就是O(logN)了
那如果取模该如何实现呢:
计算3^100%100
1、取模计算原理
(a*b)%p=[(a%p)*(b%p)]%p;
2、代码实现
#include<iostream>
long long quickPow(long long base,long long exponent,long long mod){
long long result=1;//储存最终答案
while(exponent>0){
if(exponent%2==1){//指数为奇数时
result=(result*base)%result;
}
//为偶数时
base=base*base%mod;
exponent/=2;
}
return result;
}
主要思路:
1、指数为奇数时,就分离个1,再变成偶数:
3^5=3*(3^4); 因为要取模:根据公式
(ab)%p=[(a%p)(b%p)]%p;
35%100等价于``[(3%100)*(34%100)]%100`
也就是代码:
if(exponent%2==1){//指数为奇数时
result=(result*base)%mod;
}
那result来储存奇数多余的部分(3%100)
并且由于计算机除法是向下取整,所以在后面的偶数部分实现了exponent减1
2、偶数时:
3^4=(3*3)^2=9^2
//为偶数时
base=base*base%mod;
exponent/=2;
3、具体实战:
假设我们要计算 310mod 100310mod100。这里的底数(base)是 3,指数(exponent)是 10,模数(mod)是 100。
运行 `quickPow(3, 10, 100)` 函数的步骤如下:
1. 初始设置 `result = 1`。
2. 进入 while 循环,因为 10 > 0:
- 10 是偶数,所以不进入 if 语句。
- 更新 base:base = (3 * 3) % 100 = 9。
- 更新 exponent:exponent = 10 / 2 = 5。
3. 再次进入循环,因为 5 > 0:
- 5 是奇数,所以进入 if 语句:result = (1 * 9) % 100 = 9。
- 更新 base:base = (9 * 9) % 100 = 81。
- 更新 exponent:exponent = 5 / 2 = 2。
4. 再次进入循环,因为 2 > 0:
- 2 是偶数,所以不进入 if 语句。
- 更新 base:base = (81 * 81) % 100 = 61。
- 更新 exponent:exponent = 2 / 2 = 1。
5. 再次进入循环,因为 1 > 0:
- 1 是奇数,所以进入 if 语句:result = (9 * 61) % 100 = 49。
- 更新 base:base = (61 * 61) % 100 = 21。
- 更新 exponent:exponent = 1 / 2 = 0。
6. 退出循环,因为 exponent = 0。
7. 返回结果 result = 49。