常规思路
在我们做算法题中,经常会遇到求指数幂的题目,但是如果我们用以往的方法:循环方法还是java中的Math.pow()方法,它的速度都是非常的慢的,无法达到我们满足的要求。
例如:
long normalMethod(long base,long index){
long long result=1;
for(int i=1;i<=power;i++){
result=result*base;
result=result%1000;
}
return result%1000;
}
这是我们以往想到的最简单的方法,它虽然通过求余方法解决了内存溢出的问题,但是它的运行速度通过循环的方式非常的慢,当我们想要计算2的1000000000次幂时,我们测试了一下它的运行速度大概需要18秒的时间,这是我们在算法中最不希望看到的。
快速幂算法思想
3^10=3*3*3*3*3*3*3*3*3*3
3^10=(3*3)^5
3^10=9^5
//此时指数由10缩减一半变成了5,而底数变成了原来的平方,求3^10原本需要执行10次循环操作,求9^5却只需
要执行5次循环操作,特别是在幂特别大的时候效果非常好,例如2^1000=4^500,底数只是做了一个小小的平方操
作,而指数就从1000变成了500,减少了500次的循环操作。
//但是如何把指数5变成原来的一半,5是一个奇数,5的一半是2.5,但是指数不能为小数,因此我们不能这么简单
执行5/2,然而,这里还有另一种方法能表示9^5
9^5=(9^4)*(9^1)
//此时我们我们9^5拆分成(9^4)*(9^1),这时的(9^1)指数无法在变小了,而9^4可以继续将指数变小。
9^5=(81^2)*(9^1)
//把指数缩小一半,底数执行平方操作
9^5=(6561^1)*(9^1)
//此时我们发现无法继续将这个式子的指数继续变小了。
9^5=(9^4)*(9^1)=(81^2)*(9^1)=(6561^1)*(9^1)
我们发现9产生的时候是在次幂=5的时候,而6561出现的时候是在次幂=1的时候
所以我们能发现一个规律:最后求出的幂结果实际上就是在变化过程中所有当指数为奇数时底数的乘积。
快速幂算法代码实现
long fastMethod(long base, long index) {
long result = 1;
while (index> 0) {
//当指数为奇数时
if (index % 2 == 1) {
result = result * base % 1000; //此时结果乘以底数并进行求余
}
//当指数为偶数时,指数除以2的同时,底数扩大到平法倍数
index = index / 2;
base = (base * base) % 1000;
}
return result;
}
此时我们再用这个方法测试一下2的100000000,结果发现用时0.001秒。
我们可以看出快速幂求解的方法确实是我们学习算法时的必经之路。
它的主体思想就是通过降幂的方法,将底数进行求方运算,以减少循环的次数。