对于求a^b这种问题,在b很小时可以采用循环直接计算结果,但一般题目中b会相当大,直接计算往往会超时,因此就需要采用快速幂算法。
快速幂算法能帮我们算出指数非常大的幂,一般的求幂算法之所以时间复杂度非常高(为O(指数n)),就是因为当指数n非常大的时候,需要执行的循环操作次数也非常大。而快速幂算法的核心思想就是每一步都把指数分成两半,而相应的底数做平方运算。这样不仅能把非常大的指数给不断变小,所需要执行的循环次数也变小,而最后表示的结果却一直不会变。
例如:2^10=2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2
2^10=(2 * 2) * (2 * 2) * (2 * 2) * (2 * 2) * (2 * 2)
2^10=(2*2) ^5=4 ^5
此时,指数从10缩小到了5,直接减少了一半,假如是2的100000次方,经过一次之后就变为4的50000次方,一下减少了50000次循环操作,明显节省时间。
而对于2^10 =4 ^5之后继续缩小指数,然后底数做平方,但此时指数为5,是奇数,无法除以2,这时可以这样:4 ^5=(4 ^1)* (4 ^4)
4 ^5=(4 ^1) * (16 ^2)
4 ^5=(4 ^1) * (256 ^1)
2^10=(4 ^1) * (256 ^1)=4 * 256=1024
此时可以发现,最后的结果是4*256,而4是当指数为奇数5时,此时底数为4。256是当指数为奇数1时,此时的底数为256。所以可以发现:最后求出的结果实际上就是在变化过程中当指数为奇数时底数的乘积。
#include <iostream>
using namespace std;
//快速幂
long long fastpower(long long base, long long power)//底数base 指数power
{
long long ans = 1;
while (power > 0) {
if (power % 2 == 0) {
//指数为偶数
power = power / 2;//指数缩小为一半
base = base * base;//底数变大成原来的平方
} else {
//指数为奇数
power = power - 1;//把指数减去1,使其变成一个偶数
ans = ans * base;//此时将指数为奇数时的底数与记录结果ans相乘
power = power / 2;//此时指数为偶数,可以继续执行操作
base = base * base;
}
}
return ans;
}
int main()
{
long long m,n;
cin >> m >> n;
cout << fastpower(m, n) << endl;
return 0;
}
此时代码中的重复部分仍然可以进行优化
power = power - 1;
power = power / 2;
这两行代码可以合并为一行
power = power / 2;
而且if和else中都有
power = power / 2;
base = base * base;
可以进行合并
#include <iostream>
using namespace std;
//快速幂
long long fastpower(long long base, long long power)//底数base 指数power
{
long long ans = 1;
while (power > 0) {
if (power % 2 == 1)//指数为奇数
{
ans = ans * base;
}
power = power / 2;
base = base * base;
}
return ans;
}
int main()
{
long long m,n;
cin >> m >> n;
cout << fastpower(m, n) << endl;
return 0;
}
而power%2还可以使用二进制进行优化
最终代码
#include <iostream>
using namespace std;
//快速幂
long long fastpower(long long base, long long power)//底数base 指数power
{
long long ans = 1;
while (power > 0)
{
if (power & 1)//power为奇数
{
ans = ans * base ;
}
power >>= 1;//power=power/2
base = (base * base);
}
return ans;
}
int main()
{
long long m,n;
cin >> m >> n;
cout << fastpower(m, n) << endl;
return 0;
}