快速幂

  幂运算是非常常见的一种运算,求$a^{n}$最容易想到的方法便是通过循环逐个累乘,其复杂度为$O(n)$,这在很多时候是不够的,所以我们需要一种算法来优化幂运算的过程。快速幂这个东西比较好理解,今天把它系统的总结一下防止忘记.

正文:

首先,快速幂的目的就是做到快速求幂,假设我们要求$a^{b}$,按照朴素算法就是把a连乘b次,这样一来时间复杂度是$O(b)$,即是$O(n)$级别,快速幂能做到$O(logn)$,快了好多好多.

它的原理如下:

假设我们要求$a^{b}$,将$b$写为二进制的形式,该二进制数第$i$位的权为$2^{i-1}$.

e.g. $b=11$时, $a^{11}=a^{2^{0}+2^{1}+2^{3}}$

11的二进制是1011,$11 = 2^{3} \times 1 + 2^{2} \times 0 + 2^{1} \times 1 + 2^{0} \times 1$,因此,我们将$a^{11}$转化为算 $a^{2^{0}} \cdot a^{2^{1}} \cdot a^{2^{3}}$,也就是$a^{1} \cdot a^{2} \cdot a^{8}$ .原来算11次,现在算三次,但是这三项貌似不好求.

不急,下面会有详细解释.

由于是二进制,很自然地想到用位运算这个强大的工具:&(按位与)和»(右移运算符). &运算通常用于二进制取位操作,例如一个数$x$& 1 的结果就是取二进制的最末位. 还可以判断奇偶$x$&1==0为偶,$x$&1==1为奇。 »$n$运算比较单纯,将数字写成二进制形式,右移$n$位,即将二进制去掉最后$n$位.

int binarypow(int a, int b) {
  int ans = 1, base = a;
  while (b != 0) {
    if (b & 1 != 0)
      ans *= base;
      base *= base;
      b >>= 1;
  }
  return ans;
}

代码很短,也很好理解,以$b=11$为例,$11{10}=1011_{2}$,二进制从右向左算,但乘出来的顺序是$a^{2^{0}} \cdot a^{2^{1}} \cdot a^{2^{3}}$,是从左向右的.我们不断的让$base * = base$目的即是累乘,以便随时对$ans$做出贡献.

其中要理解$base * =base$这一步:因为 $base * base$ $\Longleftrightarrow$ $base^{2}$,下一步再乘,就是$ base^{2} * base^{2}$ $ \Longleftrightarrow $ $ base^{4}$,然后同理 $ base^{4} * base^{4} $ $ \Longleftrightarrow$ $ base^{8}$,由此可以做到$base$ $\longrightarrow$ $ base^{2} $ $ \longrightarrow$ $ base^{4} $ $ \longrightarrow$ $ base^{8} $ $ \longrightarrow$ $ base^{16}$ $ \longrightarrow $ $ base^{32} \cdots$指数正是$2^{i}$,再看上面的例子,$a^{1} * a^{2} * a^{8}$,这三项就可以完美解决了,快速幂就是这样.

如果需要取模的话,直接在每一步运算中对base和ans取模即可.

转载请注明原地址,小黑特的博客:http://te-shi.com 谢谢!

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦