快速幂的原理及时间复杂度
快速幂
引例:计算219
我们的思路是,把19拆开,拆成2的整数次幂之和,即19=16+2+1,则原式219 = 216+2+1 = 216 × 22 ×21
这样,19个2相乘就转化为3个数相乘,并且,由于这3个数的计算方法与二进制有着密切联系。因此我们可以采取二进制来依次获得这3个数。
快速幂原理:对于ab,可将b转换为2进制按权相加式,其中每个有效权位对应一个中间数,通过这些中间数,我们可以大大减少运算量。从而快速进行幂运算。
对于一个十进制数b,如果找到≥b的最小整数c,其中整数c是2的整数次幂,则b可由log2c位二进制数表示(2n=c > b,log2c=n)。
令n = log2c,b = x020 + x121 + x222 + … + xn-12n-1。
再由ab = a^b = a^(x020 + x121 + x222 + … + xn-12n-1),可以减少乘法操作的次数,先是基数21~2n,先进行了n次乘法,再由有效位(b的二进制形式中,数码为1的位)的位数m,额外进行m-1次的计算,则总共计算了n+m-1次,即得到计算次数不超过log2c + m – 1次。从原来的乘n次变为现在的最多乘2log2n次,因此,时间复杂度由原来的O(b)减小为现在的O(log2b)。
例如,计算26。
对于传统计算方法,需要将6个底数2相乘即:
26 = 2×2×2×2×2×2 = 64,总共乘6次
而使用快速幂,则只需要分两步进行:
① 把6转换为2进制按权相加式:
6D = (0 × 20 + 1 × 21 + 1 × 22)D = 110B这里基数21变为22(6<23=8,n=3,n-1=2,指数依次为0,1,2),总共乘了2次。
② 计算26 = 2^6 =2^(0 × 20 + 1 × 21 + 1 × 22),
把这个式子展开,则得到22 +4 = 22 × 24
由有效位(6的二进制形式中,数码为1的位)的位数为2,则额外的乘法次数为2-1=1
快速幂,一共进行了3次乘法
又如计算21025
传统方法要乘1025次
对于快速幂,由21~210共10次,再由有效位(1025的二进制形式中,数码为1的位)的位数为2,则额外的乘法次数为2-1=1,所以共进行了11次乘法
代码如下:
1 long long qpow(long long base, long long pow) 2 { 3 long long res = 1; 4 while(pow) 5 { 6 if(pow&1) 7 res *= base; 8 base *= base ; 9 pow>>=1;11 } 12 return res; 13 }
通常,由于int类型以及long long类型的数值范围限制,通常遇到的OJ题目(例如:UPC-7778快速幂求模)需要对运算结果取模:
long long qpow(long long base, long long pow, long long mod) { long long res = 1 % mod; base %= mod; while(pow) { if(pow&1) res = (res * base) % mod; base = (base * base) % mod; pow>>=1; } return res; }
对比枚举幂运算的次数,快速幂的确可以减少运算次数
例如求86666 % 999,样例结果如下:
Enter a, b, p:
8 6666 999
Count of calculation: 44
a^b %p = 406