快速幂
1,传统方法求幂值
//代码1-1,最暴力的方法求幂值
long long pow (int a, int b){
long long result=a;
for(int i = 2; i <= b; i++){
result *= a;
}
return result;
}
上面的方法可以求出次数比较小的幂值,优点是思路简单、好实现,缺点是在计算高次幂时容易超时(时间复杂度为O(N),其中N值等于指数)。
2,快速幂
1,优势
时间复杂度 :
O
(
l
o
g
2
N
)
(
N
值
等
于
指
数
)
O(log_2N )(N值等于指数)
O(log2N)(N值等于指数)
相比于O(N),快速幂消耗的时间少很多,效率得到了极大的提高。
2,原理
在学习快速幂之前,必须知道如何将十进制转化为二进制。
以a的b次方为例。
i)第一步
将b转化为二进制,例如b=11。
11的二进制为1011(具体算法可以参照十进制与二进制之间的转化这一篇)
ii)第二步
因为
11
=
1
∗
2
3
+
0
∗
2
2
+
1
∗
2
1
+
1
∗
2
0
11=1*2^3+0*2^2+1*2^1+1*2^0
11=1∗23+0∗22+1∗21+1∗20
故可以将a的11次幂转化为
a
11
=
a
2
0
∗
a
2
1
∗
a
2
3
a^{11}=a^{2^0}*a^{2^1}*a^{2^3}
a11=a20∗a21∗a23
原本用传统方法需要运算11次的幂值用快速幂方法仅需要3次运算即可完成。
3,实现
这里涉及到另外一个知识点——位运算。
关于位运算的知识,还是参照百度百科的好(点我直达),我就不误人子弟了。
维基百科大陆也可以用了,如果百度百科没看懂可以再看一下维基百科的介绍。
计算机在处理信息时都是以二进制处理的,故以二进制进行运算会比十进制之间的运算快(即使我们输入的数据是十进制,计算机也会在运算时将十进制转化为二进制)。
//代码3-1 快速幂的实现代码
long long poww(int a, int b) {
long long base = a, index = b, result = 1;
while (index != 0) {
if (index & 1 != 0) {
result = result * base;
}
base = base * base;
index >>= 1;
}
return result;
}
这是个可以直接调用的快速幂模板代码,函数poww(据说大佬都这么命名)的类型是long long
类型,为了防止返回值太大而溢出(超出long long的最大值还是会溢出)。
while
循环中的index != 0
对应2-2-(ii),在二进制时若为0则不再进行继续运算。
if条件中的index & 1
这个条件中的&
表示按位进行或运算。
或运算在维基百科里面的具体解释:
逻辑或常在位运算中使用,比如:
0 or 0 = 0
0 or 1 = 1
1 or 0 = 1
1 or 1 = 1
1100 or 1010 = 1110
根据这条规则即可解释位index & 1
这一条件句,若二进制的最低位为1,此时1&1=1,所以进行运算result = result * base
,故进行2-2-(ii)中的第一个公式。
第二个循环时同样为1,到第三次循环时index为0,此时0&1=0,故为假,故不进行运算,因为在数学运算上此位是0*2^2=0。
index >>= 1
是位运算符,代表着由高位向地位位移一位,例如11=1011,进行此步之后就变为了101。
3,总结
快速幂是利用了计算机的特性——以二进制处理数据,并且将这一特性与数学化简结合,缩短了运算的时间。
此题不建议使用*=
或+=
这一类的运算符,因为会WA(具体原因我还没找到)。