做HDOJ的2035题时遇到了这个问题,估计是脑子比较笨,看了很多都不懂,后来终于找到了一个大神写的详细解释
http://wenku.baidu.com/link?url=W3_uQ5Xi45_oeU56uZVUumrk7duKWoRXiGrOhQpx4B2SApiUIBgnUzsK-eytYD3Yq64IzJj3hERyZyhfv3DNBwmyXsVSBJKUWGVVf39gp7q
简单地提一下思路。
以求a^b mod c为例,一步步地优化算法,从而最终得到快速幂算法。原帖是用C语言,这里用Java并没有什么区别。
1.
int res = 1; //初始化结果为1
for(int i = 1;i <= b;i++){
res = res * a;
} //通过一个O(b)的循环,令a自乘b次
res = res % c; //最终得到的结果再取模
这个算法非常好理解,也是最简单、用时最长的,下面进行改进。
2. 首先要引出一个公理,也是接下来一直需要的式子:
a^b mod c = (a mod c)^b mod c
根据这个概念我们对算法进行优化:
int res = 1;
a = a % c; //加上这一句
for(int i = 1;i<=b;i++)
{
res = res * a;
}
res = res % c;
时间复杂度没变,但是相对于(1)所产生的大数来说已经减小了很多,接下来我们继续改进:
那么每次的a mod c在自乘之后成为了一个新的a,又可以%c来减小结果。
3
int res = 1;
a = a % c; //加上这一句
for(int i = 1;i<=b;i++) {
res = (res * a) % c; //这里再取了一次余
}
ans = ans % c;
4.
a^b mod c = (a^2)^(b/2) mod c 偶数情况
a^b mod c = (a^2)^(b/2)*a mod c 奇数情况令 k = (a^2) mod c,那么结果只需要求 k^(b/2) mod c即可(偶数情况),奇数情况需要再乘a
int res = 1;
a = a % c;
if(b%2==1)
res = (res * a) mod c; //如果是奇数,要多求一步,可以提前算到res中
k = (a*a) % c; //我们取a^2而不是a
for(int i = 1;i<=b/2;i++){
res = (res * k) % c;
}
res = res % c;
时间复杂度为b/2,为了实现最终的O(log b)时间复杂度,发现b=0时所有的迭代结束
5. 快速幂算法
int res = 1;
a = a % c;
while(b>0){
if(b % 2 == 1)
res = (res * a) % c;
b = b/2;
a = (a * a) % c;
}