我们先来看,要求一个整数的 n 次幂,普通的方法的话,是不是需要乘以 n 次这个数?这里如果幂次非常大的话,肯定会非常耗时,所以有超时的危险,也是有很多卡时间的题的,所以这里就牵涉到一个快速幂的思想:
所谓快速幂,就是快速求幂次。我们知道,所有的数字,都可以用二进制来表示对吧,比如 21 ,它的二进制数字为 10101 ,也就是他可以分成 ,也就是,也就是二进制数从最后一位,权值为 1,到最高位权值为 16,可以看到如下情况:,所以这个数的二进制数的各个位上的数字,如果为 1,就加上这个位的权值,如果不为 1,就不加。
然后介绍一下 ‘&’ 这个符号的意义,这个符号就是将对应二进制位对齐,然后同一位上都为 1 则结果为 true ,否则为 false 比如 10101 & 1 = 1 , 10100 & 1 = 0。‘>>’这个符号的意义是将整个二进制数字右移,也可以理解为除以 2 ,就是将最后一位剔除的意思,比如 10101 >> 1 = 1010。
所以我们可以用 & 来取出最后一位的数字,然后用 >> 右移来一步一步进行提取,然后如果最后一位上的数字为 1,则为真,否则为假。而我们一般分解的数字是幂次的数字,也就是如果要求我们分解的是 21,然后权值就会变成,,,,,所以如果判断为真(最后一位为1)则乘以对应的权值,如果判断为假,则不乘。
注意:不管当前位是不是 1,都要权值都要自乘,因为权值要一直改变。
所以当我们需要求的时候,我们将它分为,此处 res = 1,所以只需要计算 3 + 4(自乘) 次乘法,而不是 21 次。
普通版代码:
/**普通算法*/
#define ll long long int
ll power1(ll a, ll b) ///a为底数,b为幂次
{
ll res = 1;
for(ll i = 1; i <= b; i++) ///乘以b次底数
{
res *= a;
}
return res;
}
快速幂算法:
/**快速幂优化后算法*/
#define ll long long int
ll power2(ll a, ll b) ///a为底数,b为幂次
{
ll res = 1; ///res为最终结果
a %= c; ///a为需要取余的数字
while (b)
{
if (b & 1) ///判断最后一位
res = res * a;
a = a * a; ///a自乘
b >>= 1; ///b应当右移一位
}
return res;
}
优化后算法时间复杂度可以从变成,当数据大的时候,优化其实是特别明显的。
OVER!