快速幂的原理及时间复杂度

快速幂

引例:计算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

 

posted @ 2019-05-16 21:17  NESTER  阅读(3011)  评论(0编辑  收藏  举报