1.通俗解释
快速幂就是加快指数运算,一般情况下指数运算的结果都很大,顺便学一下取模运算的一些法则:
(a + b) % p = (a % p + b %p) % p (1)
(a - b) % p = (a % p - b % p ) % p (2)
(a * b) % p = (a % p * b % p) % p (3)
下面进入正题
举个例子:
3
14
=
(
3
2
)
7
=
9
7
=
9
1
∗
9
6
=
9
1
∗
8
1
3
=
9
1
∗
8
1
1
∗
8
1
2
=
9
1
∗
8
1
1
∗
656
1
1
\ 3^{14} =(3^{2})^7= 9^7 =9^1*9^6=9^1*81^3=9^1*81^1*81^2=9^1*81^1*6561^1
314=(32)7=97=91∗96=91∗813=91∗811∗812=91∗811∗65611
(1)如果指数是偶数便可以通过底数平方、指数减半的方法来减少一半的计算量。
(2)如果指数是奇数,那便可以拆分为一次方和一个偶数,然后在继续进行运算减半。
结论:运算直到最后全是一次方,这些一次方其实都是指数为奇数时拆出来的,所以在指数减半时遇到指数是奇数的话就将此时的底数累乘,这便是最终结果。
2.代码实现
照着上面的思路很容易写出代码:
ll fastPower(ll base, ll power) {
ll result = 1;
while (power > 0) {
if(power % 2 == 1) { //指数为奇数
power -= 1;
result *= base;
}
else {
power /= 2;
base *= base;
}
}
return result;
}
但不妨考虑进一步优化,由于C语言中整数的除运算依然是整数,所以当指数power是奇数时,(power-1)/2和power/2的结果是一样的,所以遇到指数是奇数就直接结果累乘,所有情况都直接指数减半,底数平方。如下:
ll fastPower(ll base, ll power) {
ll result = 1;
while (power > 0) {
if(power % 2 == 1) result *= base;
power /= 2;
base *= base;
}
return result;
}
最后的最后,使用位运算还能加快运算!!!
最终代码
ll fastPower(ll base, ll power) {
ll result = 1;
while (power > 0) {
if(power & 1) result *= base;
power >>= 1; //等价于除2
base *= base;
}
return result;
}