求 pow(x,n) 先来说说快速幂,正常的做法线性速度,O(n)的时间复杂度。快速幂的时间的复杂度O(log2(n))
其数学推导如下:
当n为偶数时 若2k = n 即k = n/2 则x^(2k) = x^(k)x^(k);
当n为奇数时 若2k+1=n 即k = n/2 则x^(2k+1) = x^(k)x^(k)*x;
递归结束条件 : n = 0 return 1.0
这里还需注意一下 n可能为正 也可能为负
具体程序 见代码:
//采用递归很巧妙的方法
public double myPow(double x, int n) {
if(n<0){
return 1/calcPow(x, -n); //需要注意 n为负的情况
}else{
return calcPow(x, n);
}
}
public double calcPow(double x, int n){
if(n==0){
return 1.0;
}
double val = calcPow(x, n/2);
if(n%2==0){
return val*val;
}else{
return val*val*x;
}
}
而对于快速幂取模。求(a^n)%M
对于求模,有个很关键的公式 (ac)%m = (a%m)(c%m)%m
同时呢: (a+d)%m = ((a%m)+(d%m))%m
数学推导如下:
若n为偶数: 假设 n = 2k (a^2k)%m = ((a^k)%m)((a^k)%m)%m
若n为奇数: 假设 n = 2k+1 (a^(2k+1))%m = (((a^k)%m(a^k)%m)%m*a%m)%m
递归结束条件 : n = 0 return 1.0
具体程序见代码: 递归方法 method1:
public int modPow(int x,int n,int m){
return modOfQuickPow(x, n, m);
}
//快速幂取模的方法 求(x^n)%m 这里的n假设为非负数 m假设为正整数 x为正整数
private int modOfQuickPow(int x,int n,int m){
if(n==0){
return 1;
}
if(n==1){
return x%m;
}
if(n%2==0){
// (a^2k)%m = ((a^k)%m)*((a^k)%m)%m
return (modOfQuickPow(x, n/2, m)%m)*(modOfQuickPow(x, n/2, m)%m)%m;
}else{
//(a^(2k+1))%m = (((a^k)%m*(a^k)%m)%m*a%m)%m
return (modOfQuickPow(x, n/2, m)%m)*(modOfQuickPow(x, n/2, m)%m)%m*(x%m)%m;
}
}
递归 method2
//快速幂取模 方法二
private int modOfQuickPow1(int x,int n,int m){
if(n==0){
return 1;
}
if(n==1){ //如果这个条件没有会无限递归下去 比如1 n/2 = 0 而 n-n/2 = 1 死循环
return x%m;
}
return (modOfQuickPow1(x, n/2, m)%m*modOfQuickPow1(x, n-n/2, m)%m)%m;
}