「数学::快速幂」基本快速幂运算|快速幂取模运算(C++)

思路

你应该很早就注意到一个问题:依靠朴素循环的线性级别的指数运算是不必要的。

例如,

pow(3,4)=3*3*3*3
        ↓
pow(3,4)=9*9

这样循环的工作量明显大幅下降了。

*注意*: 与少量循环的大值相乘相比,大量循环的小值相乘要慢得多。

我们今天就来研究这个问题。

1.快速幂

算法过程

快速幂运算就是依靠上述思路进行的算法,但我们要着重探讨关于指数的问题。

那么按照思路,快速幂的过程就应该是 

int ans=1;
每次循环中应该是ans*=如下数
pow(x,1) → pow(x,2) → pow(x,4) → pow(x,8)

但是观察:

           -   -------   ---------------
pow(x,13)= x * x*x*x*x * x*x*x*x*x*x*x*x
         = pow(x,1) * pow(x,4) * pow(x,8)

嘶,我们怎么就知道可以省略pow(x,2)才能凑整呢? 

这时候一个精妙之处就来了:13转二进制位是1101。

                          (8    4   2    1)
而1101的位权从左到右分别对应2^3,2^2,2^1,2^0。
                           1    1   0    1

即13=1*2^3+1*2^2+0*2^1+1*2^0。

观察二进制位我们发现:

将n转为二进制位时,0的位置被忽略,因此省略pow(x,2)才能凑整。

来看Code。

Code

int quick_pow(int x,int n){
   int ans=1;
   while(n){
      if(n&1)ans*=x;//如果n的末尾是1,那么不能忽略现在的x
      x*=x;         //x指数翻倍
      n>>=1;        //n右移一位,1101→110,那么下次循环时忽略,即忽略pow(x,2)
   }
}

2.快速幂取模

算法过程

那么我们怎么计算pow(x,n)%m呢?(即 pow(x,n) mod m)

首先,你至少要知道:

a * b % m = ((a % m) * (b % m)) % m

相乘后取模=分别取模后再相乘最后再取模。 

那么,我们的过程就应该是:

pow(x,13)%m = ({pow(x,5)%m}*{pow(x,8)%m})%m
               ------------
                    ↓
            = ({[(pow(x,1)%m)*(pow(x,4)%m)]%m}*pow(x,8)%m)%m
               -------------------------------

            = (((1%m*(x^1)%m)%m*(x^4)%m)%m*(x^8)%m)%m
                --第一次循环----
               -------第三次循环-----------
              ------------第四次循环------------------

那我们只需要将Code稍加改动即可。

Code

int quick_pow_mod(int x,int n,int m){
   int ans=1;
   x=x%m;
  //ans=ans%m可以忽略
   while(n){
      if(n&1)ans=(ans*x)%m;//这里ans和x已经在上一次循环对m取模了
      x=(x*x)%m;           //pow(x,k)%m
      n>>=1;               //n右移一位
   }
}

复杂度 

时间复杂度: O(logn)
空间复杂度: O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值