本篇来说一下快速幂的原理,如果发现我叙述的听不明白,可以先去我之前的博客文章,有关数制了解一下
https://blog.csdn.net/assiduous_me/article/details/102295812
快速幂:快速幂就是快速算底数的n次幂。其时间复杂度为 O(log₂N), 与朴素的O(N)相比效率有了极大的提高
原理:
对于 a^b 计算,一般做法是让 b 个 a 连续相乘
例如:3^10 一般做法,3^ 10 = 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3
但是这样的做法难免太慢了,为什么这么说呢?
我们可以这样做:3^10 = 3^(1*2^3 + 0*2^2 + 1*2^1 + 0*2^0) = 3^(2^3) * 3^(2^2)
将次幂 10 变成二进制数字 1010,将次幂进行拆解,拆解为 1*2^3 + 0*2^2 + 1*2^1 + 0*2^0
次幂加减对应的实际操作为对应数值相乘或相除操作
3^10 = (3^8) * (3^0) * (3^2) * (3^0)
代码:
private static int pow(int n, int m)
int res = 1;
int base = n;
while(m != 0) {
if ((m&1) == 1) {
res = res * base;
}
base = base * base;
m = m >> 1;
}
return res;
}
现在对代码进行解释:
n 表示底数,m 表示次幂
base = n 表示的是 n^(2^0)
m & 1 == 1 是判断 m 的二进制的最后一位是否为 1
m >> 1 是将 m 的二进制的最后一位移除,对于 1010 ,1010 >> 1 = 0101
下面带大家走一波手动 debug,pow(3, 10)
初始化:res = 3^0 = 1, base=3^(2^0)=3
m = 1010(2)
此时 m 不等于 0
判断 m & 1 ,因为 m 的末尾为 0,所以不等于 1
执行 base = base * base,此时 base =3^(2^0) * 3^(2^0) = 3^(2^1)
m >> 1 得 m = 101(2)
此时 m 不等于 0
判断 m & 1,因为 m 的末尾为1,所以执行
res = res * base,此时 res = 3^(2^1)
执行 base = base * base ,此时 base = 3^(2^1) * 3^(2^1) = 3^(2^2)
m >> 1 得 m = 10(2)
此时 m 不等于 0
判断 m & 1,因为 m 的末尾为 0,所以不等于 1
执行 base = base * base,此时 base = 3^(2^2) * 3^(2^2) = 3^(2^3)
m >> 1 得 m = 1(2)
此时 m 不等于 0
判断 m & 1,因为 m 的末尾为1,所以执行
res = res * base,此时 res = 3^(2^1) * 3^(2^3) = 3^10
执行 base = base * base ,此时 base = 3^(2^3) * 3^(2^3) = 3^(2^4)
m >> 1 得 m = 0(2)
此时 m 等于 0
所以返回 res = 3^10,结束!!!
这下看懂了吧,神奇又巧妙,所以说学好数学很重要的,可惜我大学学高数的时候学的太差(;′⌒`),ok,如果大家有什么不明白的地方,可以在下面评论,我看到会回复你们的,(*^_^*)