一、算法简介
1.使用pow函数和自定义的for循环的时间复杂度为O(n)
/**计算x的y次方**/
//1.使用Pow函数
double res = Math.pow(x,y);
//2.自定义for循环
double res=x;
for(int i=1;i<y;i++){
res=res*x;
}
2.快速幂的时间复杂度为O(log n)
二、快速幂的思想
(1)从分冶的角度出发,计算
①假设y为偶数,即计算
=
我们将指数 y,每次划分为 ,上述式子不需要进行8次循环,而只需要三步即可完 成,注 和 是为了让读者好理解,而重复写的。
②假设y为奇数,即计算
=
指数部分为奇数是可以化解成(1+偶数)的形式的,这样我们可以把指数为1的底 拿出来当答案来乘,偶数部分同①继续化解即可
伪代码
x=3,y=10,res=1
while(指数y不等于0){
if(指数y为奇数){
res = res * x //提取底数出来,作为乘积
}
y=y/2 //指数二分
x=x*x //底数平方
}
(2) 从二进制的角度出发
如8的二进制位:8=;
二进制转十进制:==8
那么== (倒序写)
观察发现:指数部分是由两部分组成,第一部分是0001,第二部分是 ,发现2是循环增大的(用代码x=x*x,循环迭代出来,但是否使用则看二进制位是否为‘1’),由于二进制要么为0要么为1(用代码 y&1==1,来判断)
再举个详细的例子(计算):
11=1011
=
伪代码:
x=3,y=11,res=1
while( (1011)y从尾往头读取){
if( (y&1)==1){
res=res*x; //二进制位不为0,则相乘
//如第一个1:res=1*3,
//第二个1:res=res*3^2
//第三个数为0:不相乘,但x是不断平方的,此时是x^4
//第四个数为1:res=res*3^8 ,注意哦,平方是在if后面
}
二进制右移一位
x=x*x; //依次迭代3^0,3^1,3^2,3^4,3^8................
}
三、代码实现
public static double FastPow(int x,int y){
double res= 1;
while (y!=0){
if(y%2 == 1){ //指数为奇数,也可以利用位运算:(y&1)==1 (与操作): 判断 n 二进制最右一位是否为 1
res *= x;
}
y=y/2; //指数循环二分,y>>=1 (移位操作): n 右移一位(可理解为删除最后一位,即除以2)。
x=x*x; //底数平分
}
return res;
}