快速幂
快速幂
递归快速幂
递归
无非是一个二分的思路。我们很自然地可以得到一个递归方程:
\[a^{n}=\begin{cases} a^{n-1} \cdot a \quad if \ n \ is \ odd\\ a^{ \frac{n}{2}}\cdot a^{ \frac{n}{2}} \quad if \ n \ is \ even\ but\ not\ 0\\ 1 \quad if \ n \ = \ 0\end{cases}
\]
计算a的n次方,如果n是偶数(不为0),那么就先计算a的n/2次方,然后平方;如果n是奇数,那么就先计算a的n-1次方,再乘上a;递归出口是a的0次方为1。
int qpow(int a, int n)
{
if (n == 0)
return 1;
else if (n & 2 == 1)
return qpow(a, n - 1) * a;
else
{
int temp = qpow(a, n / 2);
return temp * temp;
}
}
在实际问题中,题目常常会要求对一个大数取模,这是因为计算结果可能会非常巨大,但是在这里考察高精度又没有必要。这时我们的快速幂也应当进行取模,此时应当注意,原则是步步取模,如果MOD较大,还应当开long long。
static int num;
int qpow(int a, int n)
{
if (n == 0)
return 1;
else if (n & 2 == 1)
return qpow(a, n - 1) * a%num;
else
{
int temp = qpow(a, n / 2)%num;
return temp * temp%num;
}
}
大家知道,递归虽然简洁,但会产生额外的空间开销。我们可以把递归改写为循环,来避免对栈空间的大量占用,也就是非递归快速幂。
非递归
我们换一个角度来引入非递归的快速幂。还是7的10次方,但这次,我们把10写成二进制的形式,也就是 \((1010)_{2}\) 。
现在我们要计算 \(7^{(1010)_{2}}\),可以怎么做?我们很自然地想到可以把它拆分为 \(7^{(1000)_{2}}⋅7^{(10)_{2}}\) 。实际上,对于任意的整数,我们都可以把它拆成若干个 \(7^{(100...)_{2}}\) 的形式相乘。而这些 \(7^{(100...)_{2}}\),恰好就是 \(7^{1}\) 、\(7^{2}\)、\(7^{4}\)……我们只需不断把底数平方就可以算出它们。
//非递归快速幂
static long powMod(long a, int b) {
long ret = 1;
while (b != 0) {
if ((b & 1) == 1)
ret *= a;
b >>= 1;
a = a * a;
}
return ret;
}
这里的位运算符,>>是右移,表示把二进制数往右移一位,相当于/2;
取模版本的
static long powMod(long a, int b, final long mod) {
long ret = 1;
while (b != 0) {
if ((b & 1) == 1)
ret = ret * a % mod;
b >>= 1;
a = a * a % mod;
}
return ret % mod;
}

浙公网安备 33010602011771号