本文正在参加 人工智能创作者扶持计划
本文阅读时间约8分钟,你将获得:
全网最通俗易懂的快速幂基本思想讲解,不懂不要小钱钱的那种~
快速幂算法的应用将在后续文章进行叙述。
- 快速幂取模
- 矩阵快速幂
- 高精快速幂
算法课的老师的作业,让班里每个人都上去做算法分享的presentation
本来只想讲个分治法浑水摸鱼,没想到同学一个比一个卷,随机森林,梯度下降,密码学......反正一个比一个🐂🍺plus啦,真真就,台下全讲冒泡,台上动规起步呗......听说大佬们还觉得梯度下降太简单,又准备了个plan b ,卷死我算了....
但是作业还是要交的啊,泪奔,我水平有限,就只能剑走偏锋。本文就是记录一下被迫营业的快速幂算法TAT。
简介
快速幂,顾名思义,快速计算幂的算法,也就是说当a或b都很大时,计算的值或估算其位数的方法,它可能包含了某些动态规划或者分治的思想。
传统计算可能要做b次乘法,也就是说其时间复杂度是,而快速幂的算法时间复杂度却能做到,问题规模越大,快速幂的优势越明显
但:较复杂类型的快速幂的时间复杂度不再是,它与底数的乘法的时间复杂度有关,此句的解释可见本文递归算法思想一节。
算法思想(非递归)
我看到很多的教程都是从递归开始讲起,但我觉得非递归会更好理解一点。
非递归思想描述
将指数分解成二进制数的形式,例如,然后按照二进制位逐个处理,如果当前二进制位为,则将底数累乘;否则将底数平方。
那么对于任意一个底数a和正整数n,我们都可以使用如下公式计算
通俗理解
从例子入手,如果问你的值,你会不会将5乘上13次?
但如果将指数分解成二进制数的形式:
又因为:
也就是说我们可以将分解为四次运算(13转化为二进制有4位),每次运算的结果都是上一步结果的平方,这样我们就可以利用上一步的结果,快速获得最终值,算法的时间复杂度也因此降到了的级别。
代码实现
// 非递归快速幂
int qpow(int a , int n){
int res = 1;
while (n) {
if (n & 1) res = res * a; // 如果当前位为1,则将a乘到res上
a = a * a; // a自乘
n >>= 1; // n右移一位
}
return res; // 返回结果
}
// 这个实现使用while循环来迭代地计算a^b 的结果。
// 它从res = 1开始,如果b的当前位为1,则将a乘到res上。
// 它在每次迭代中将a平方并将b除以2(右移一位)。
// 在处理完b的所有位之后,返回最终结果。
// 这个实现的时间复杂度为O(log n)。
算法思想(递归)
递归思想描述
假设要计算的值,其中为正整数。首先将转换为二进制表示,例如,则有: ,接下来,可以通过反复平方的方式,计算出的值,并根据的二进制表示,选择将哪些幂次相乘,从而得到的值。具体地,算法的流程如下:
-
对进行二进制分解,得到的二进制表示;
-
初始化和;
-
从的二进制表示的最高位开始遍历,对于第位:
-
如果第位为0,则将的值更新为;
-
如果第位为1,则将的值更新为;
-
-
最终的结果为。
由于每次迭代都可以将幂次减半,因此算法的时间复杂度为。与朴素算法相比,快速幂算法在计算幂次时可以大大减少乘法的次数,从而实现更高效的计算。
上面的叙述可能不是那么容易懂,但它其实是非递归思想的一个逆过程。
通俗理解
更具体地,我们可以用下面的公式来描述快速幂算法:
当然对于上面的公式也可以这样想:
当你计算时可能先使用分治算法,
13是奇数,那我可以计算次,此时的底则变为,
原问题转化成
而这个7次我还可以继续往下分,计算次 ,此时原问题转化成
当然这个4次我还可以继续往下分,原问题转化成
......
经过上面的演示我们可以看出,使用递归思想的快速幂算法实质上是使用分治法减小幂,同时伴随着底的增大的过程。
这里就引申出另一个问题,虽然问题规模在不断变小,时间复杂度降为了log级别,但当底越来越大时,对其进行平方可能还会受制于大数乘法的时间限制。关于大数乘法相关描述将在后续文章中提及。
代码实现
// 递归快速幂
int qpow(int a , int n){
if (n == 0) // 如果n为0,则返回1
return 1;
else if (n % 2 == 1) // 如果n为奇数,则返回qpow(a, n - 1) * a
return qpow(a, n - 1) * a;
else { // 如果n为偶数,则返回qpow(a, n / 2) * qpow(a, n / 2)
int temp = qpow(a, n / 2);
return temp * temp;
}
}
快速幂的应用
快速幂算法可以应用于很多计算中,例如计算幂、取模运算等。
- 在计算机科学中,快速幂算法可以用于计算大数的幂,例如RSA加密算法。
- 高精快速幂(洛谷p1045)
- 在数论中,快速幂算法可以用于计算模幂,
- 计算的值。(洛谷p1226)
- 在动态规划中,快速幂算法可以用于求解斐波那契数列问题。
- 矩阵快速幂求解fibonacci
- 在图论中,快速幂算法可以用于计算邻接矩阵的幂。