快速幂(Exponentiation by squaring)是一种简单而有效的小算法,它可以以O( l o g n \mathrm{log}n logn)的时间复杂度计算乘方。快速幂不仅本身非常常见,而且后续很多算法也都会用到快速幂。
思考:7的10次方怎样算比较快?
方法1:最简单的方法,将7自乘9次,很明显,这种方法的时间复杂度为
O
(
n
)
O(n)
O(n),是这道题能达到的最高的时间复杂度了。
那么有没有什么办法能够降低时间复杂度呢?
方法2:
7
10
=
7
5
×
7
5
7^{10}=7^5\times7^5
710=75×75,而
7
5
=
7
2
×
7
2
×
7
7^5=7^2\times7^2\times7
75=72×72×7,如果我们先计算
7
2
7^2
72,再计算
7
3
7^3
73,再计算
7
5
7^5
75,最后计算
7
10
7^{10}
710,那么只需要计算4次乘法就可以得到最终的结果。这样计算的时间复杂度为
O
(
l
o
g
n
)
O(\mathrm{log}n)
O(logn)。
递归快速幂
上面我们用到递归的思想,递归方程为:
a
n
=
{
a
n
−
1
×
a
,
i
f
n
i
s
o
d
d
a
n
2
×
a
n
2
,
i
f
n
i
s
e
v
e
n
b
u
t
n
o
t
0
1
,
i
f
n
=
0
a^n=\begin{cases}a^{n-1}\times a,\ \mathrm{if}\ n\ \mathrm{is \ odd}\\a^{\frac{n}{2}}\times a^{\frac{n}{2}},\ \mathrm{if}\ n\ \mathrm{is\ even\ but\ not\ 0}\\1,\qquad\quad\ \,\mathrm{if}\ n=0\end{cases}
an=⎩⎪⎨⎪⎧an−1×a, if n is odda2n×a2n, if n is even but not 01, if n=0
代码
int quickPow(int a, int n){
if (n == 0)
return 1;
else if (n % 2 == 1)
return quickPow(a, n - 1) * a;
else
{
int temp = quickPow(a, n / 2);
return temp * temp;
}
return -1;
}
我们知道,递归虽然方便,但会调用大量的栈空间,为了减小栈的调用,我们还可以使用非递归方法。
代码
int quickPow(int a, int n){
int ans = 1;
while (n)
{
if (n & 1)
ans *= a;
a *= a;
n >> 1;
}
return ans;
}