先来看看如何(快速)求幂
求a的n次幂,最直接的想法就是把a连续乘n次,这思路自然是正确的,但是时间复杂度是O(n)的,比起快速幂的O(lg n)的算法简直不能忍,所以下面就要介绍快速幂啦。
快速幂顾名思义就是很快的求幂(废话!),我在网上其他地方看的有关位运算的快速幂感觉理解不能啊,所以我用了一种我觉得稍微好理解一点的方法(二分求幂),二分求幂是将原有的a^n分为a^(n/2)*a^(n/2),而a^(n/2)只用计算一次,原结果为a^(n/2)*a^(n/2)(由于代码中为整除,所以指数如果是奇数的话还要再乘上一个a),所以自然减少了时间复杂度。
先上代码
1 int pow(int a,int n) 2 { 3 if(a==1 || !n)return 1; 4 int tmp=pow(a,b>>1); 5 tmp*=tmp; 6 if(b&1)return tmp*a; 7 else return tmp; 8 }
第3行:如果a==1或者n==0那么结果一定为1;
第4行:用tmp来存储a^(b/2)(注意>>是位运算中右移操作符,b>>1等价于b整除2,但是速度比b/2更快)
第5行:tmp自乘tmp。
第6行:考虑奇偶,如果b为奇数再乘上一个a。(注意&也是位运算符,b&1等价于b是奇数)
这样,我们就可以在lg n的时间内求出b的n次幂了。
只是求个幂是远远不够的,如果我们还要对结果取模,怎么解决呢。
很自然可以想到先求快速幂,然后取一个模就好了,思路是正确的,但是如果求幂求出来的数超过了数据结构所能表示的范围的话就蛋疼了,要么写高精度,要么就只有看着自己的结果爆成负数。解决这一个问题,就要请出我们的求余的运算法则了
(a*b)%m=(a%m * b%m)%m
既然幂求出来再模行不通,那么我们就边算边模!下面是代码
1 int pow(int a,int b,int m) 2 { 3 if(a==1 || !b)return 1; 4 int tmp=pow(a,b>>1,m)%m; 5 tmp*=tmp; 6 tmp%=m; 7 if(b&1)return (tmp*(a%m))%m; 8 else return tmp%m; 9 }
配合上面的运算法则,程序就很好理解了。凭借这个函数,我们可以很快的求出一个数的幂并去模。
That's All!