快速幂
原理分析
求a^n的值,按照传统的写法就是用一个数ans = 1 ,乘n次a,这样的时间复杂度为O(n),而快速幂算法是基于二进制,可以将时间复杂度将为log(n)
举个例子,我们要求3^11,我们可以写成 3^(2^3+2^1+2^0),拆开后就是3^(2^3) = 3 ^ 8 、3^(2^1)=3^2 、 3^(2^0) = 3^1 , 这样看来,如果我们只计算这三个的乘积,岂不是只需要计算3次?而且这三个数之间是很有规律的,
比如 (3^1)^2 = 3^2 , ( (3^2)^2) ^2 = 3 ^8,就是对一个数不断的取二次幂,由于任意整数都可以用二进制的数来表示,也就是说我们可以将任意整数拆解成3^(2^3+2^1+2^0)这样的形式(为了方便,我们将要求的数记作a^n) , 而对于2^k是否出现,取决于n在二进制表示下第k+1位数是否为1 。 为了更加清晰的解释,我们分析一下 11 这个数,其二进制的表示形式为 1011 , 对应出现了第4 , 2 , 1 位数,于是与之对应的2^3 , 2^1 , 2^0 也就出现了。
上面我们解释了任意整数都可以写成 a ^ (2 ^ m + 2 ^ k .... )的形式,而且对于 m+ 1= k 的情况时,存在
(a^(2^m)) ^ 2 = a^(2^m+1) = a^(2^k) , 再根据2^k的出现规律,我们只需要将2^k从 k = 0 开始,不断地取二次幂,如果n在二进制下的第k+1位数为1,我们用ans记录当前的值,这时候将a(2^k)乘入ans 中,最后我们就得到了最终的答案
代码区
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
ll pow_fast(ll a, ll n)
{
ll ans = 1;
while (n != 0)
{
if (n & 1 != 0)ans =ans*a;
a = a * a;
n >>= 1;
}
return ans;
}
int main()
{
cout << pow_fast(2, 5) << endl;
return 0;
}