小白算法-快速幂

快速幂,二进制取幂(Binary Exponentiation,也称平方法),是一个在 O(logn)的时间内计算 (a^n) 的小技巧,而暴力的计算需要  的时间。而这个技巧也常常用在非计算的场景,因为它可以应用在任何具有结合律的运算中。其中显然的是它可以应用于模意义下取幂、矩阵幂等运算,我们接下来会讨论。

算法描述

计算a的n次方表示n个a乘在一起:a^n = a * a * a ...*a,然而当a,n太大的时候,这种方法就不太是不太适用了,我们将取幂的任务按照指数的二进制表示 来分割成更小的任务

首先我们将n表示为2进制,举个例子:

        3 ^ 13 = 3(1101)2 = 3 ^ 8 * 3 ^ 4 * 3 ^ 1

因为n有[log2 n] + 1 个二进制位,因此我们知道了a^1,a^2,a^4,a^8...... a^ 2[log2 n]后,我们只要计算O(log n)次乘法就可以计算出a^n

于是我们只需要知道一个快速的方法来计算上述3的2^k次幂的序列。这个问题很简单,因为序列中(除第一个)任意一个元素就是其前一个元素的平方。举一个例子:

         3^1 = 3

         3^2 = (3^1)^2 = 3^2 = 9

         3^3 = 3^1 * 3^2 = 3^3 = 3 * 9 = 27

         3^4 = (3^2)^2 = 9^2 = 81

         3^5 = 3^1 * 3^4 = 3^5 = 3 * 81 = 243

         3^8 = (3^4)^2 = 81^2 = 6561

因此为了计算3^13,我们只需要将对应二进制位为1的整系数乘起来就行了:

         3^13 = 6561 * 81 * 3 = 1594323

代码实现

 首先我们可以直接按照上述递归方法实现:

// C++ Version
long long binpow(long long a, long long b) {
  if (b == 0) return 1;
  long long res = binpow(a, b / 2);
  if (b % 2)
    return res * res * a;
  else
    return res * res;
}

第二种实现方法是非递归式的。它在循环的过程中将二进制位为 1 时对应的幂累乘到答案中。尽管两者的理论复杂度是相同的,但第二种在实践过程中的速度是比第一种更快的,因为递归会花费一定的开销。

// C++ Version
long long binpow(long long a, long long b) {
  long long res = 1;
  while (b) {
    if (b & 1) res = res * a;
    a = a * a;
    b >>= 1;
  }
  return res;
}
 
posted @   高级摸鱼怪  Views(171)  Comments(0Edit  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示