一、快速幂算法引入
假如我们有一个需要求2^100的后三位的问题,我们可以利用%运算的性质:
( a ∗ b ) % p = ( a % p ∗ b % p ) % p (a * b)\%p = (a\%p * b\%p)\%p (a∗b)%p=(a%p∗b%p)%p
这意味着我们如果想对 2 100 2^{100} 2100 直接取后三位,也就是取余1000,可以对它的每个因子取余1000,然后把这些因子乘起来再取余1000,得到的结果和直接对 2 100 2^{100} 2100取余1000是一样的。
常规思路是循环100次,模拟乘100次2的过程。
但是这样思路写的代码经过时间测试用时有点长,我们能否优化这个O(N)的算法呢?
#include <iostream>
#include <ctime>
using namespace std;
long long normalPower(long long base, long long power)
{
int res = 1;
for (int i = 1; i <= power ; ++i)
{
res *= base;
res %= 1000;
}
return res;
}
int main()
{
clock_t start = clock();
cout << normalPower(2, 1000000000) << endl;
clock_t end = clock();
cout << "The cost of calculate is " << double(end - start) / CLOCKS_PER_SEC << endl;
}
二、快速幂算法
核心思想就是如果幂次是偶数,那么我们可以让底数变成原来的平方,如果幂次是奇数,那么我们可以分解出一个底数,让它与返回结果相乘,然后幂次就是偶数了,通敌,让底数变为原来的平方,当幂次分到0的时候,就意味着我们不能再分解了,结束循环。
long long QuickPower(long long base, long long power)
{
int res = 1;
while (power > 0)
{
if (power % 2 == 0)
{
/*偶数情况 则底数平方 幂次变为原来的一半*/
base = base * base % 1000;
power /= 2;
}
else
{
/*指数是奇数情况 则拿出一个底数 使得指数变成偶数 然后就可以按照偶数那样操作*/
res = res * base % 1000;
--power;
base = base * base % 1000;
power /= 2;
}
/*直到幂次被削为0次幂时,循环结束,0次幂的时候就无法再进行削指数的操作了*/
}
return res;
}
优化一下重复部分,发现只有奇数有额外操作,可以简化为:
long long QuickPower(long long base, long long power)
{
int res = 1;
while (power > 0)
{
if (power % 2 == 1)
{
res = res * base % 1000;
--power;
}
base = base * base % 1000;
power /= 2;
/*直到幂次被削为0次幂时,循环结束,0次幂的时候就无法再进行削指数的操作了*/
}
return res;
}
再优化一下,可以把power % 2 == 1优化为:power & 1 == 1,然后再优化成power & 1,然后power /= 2优化为power >>= 1
long long QuickPower(long long base, long long power)
{
int res = 1;
while (power > 0)
{
if (power & 1)
{
/*幂次为奇数时 需要把一个底数提取出来 然后让power - 1变为偶数*/
res = res * base % 1000;
--power;
}
/*偶数情况则直接让底数平方 指数除2*/
base = base * base % 1000;
power >>= 1;
/*直到幂次被削为0次幂时,循环结束,0次幂的时候就无法再进行削指数的操作了*/
}
return res;
}
时间复杂度分析:快速幂算法的时

本文详细介绍快速幂算法原理及其在计算大整数幂次、矩阵幂次的应用,并通过具体实例展示如何利用快速幂算法提高计算效率。
最低0.47元/天 解锁文章
549

被折叠的 条评论
为什么被折叠?



