原题:给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
/*剑指书中细节:
*1.当底数为0且指数<0时
*会出现对0求倒数的情况,需进行错误处理,设置一个全局变量;
*2.判断底数是否等于0
*由于base为double型,不能直接用==判断
*3.优化求幂函数
*当n为偶数,a^n =(a^n/2)*(a^n/2)
*当n为奇数,a^n = a^[(n-1)/2] * a^[(n-1)/2] * a
*时间复杂度O(logn)
*/
public class Solution {
boolean invalidInput=false;
public double Power(double base, int exponent) {
if(equal(base,0.0)&&exponent<0){
invalidInput=true;
return 0.0;
}
int absexponent=exponent;
if(exponent<0)
absexponent=-exponent;
double res=getPower(base,absexponent);
if(exponent<0)
res=1.0/res;
return res;
}
boolean equal(double num1,double num2){
if(num1-num2>-0.000001&&num1-num2<0.000001)
return true;
else
return false;
}
double getPower(double b,int e){
if(e==0)
return 1.0;
if(e==1)
return b;
double result=getPower(b,e>>1);
result*=result;
if((e&1)==1)
result*=b;
return result;
}
}
这样的解法依然不是最优.
牛客网下评论置顶第一的是
/**
* 1.全面考察指数的正负、底数是否为零等情况。
* 2.写出指数的二进制表达,例如13表达为二进制1101。
* 3.举例:10^1101 = 10^0001*10^0100*10^1000。
* 4.通过&1和>>1来逐位读取1101,为1时将该位代表的乘数累乘到最终结果。
*/
public double Power(double base, int n) {
double res = 1,curr = base;
int exponent;
if(n>0){
exponent = n;
}else if(n<0){
if(base==0)
throw new RuntimeException("分母不能为0");
exponent = -n;
}else{// n==0
return 1;// 0的0次方
}
while(exponent!=0){
if((exponent&1)==1)
res*=curr;
curr*=curr;// 翻倍
exponent>>=1;// 右移一位
}
return n>=0?res:(1/res);
}
原理如下:
(1).快速幂
快速幂,顾名思义就是快速的求次幂,例如:a^b,普通的算法就是累乘,这样的计算方法的时间复杂度就是O(n),而快速幂的方法使得次幂的计算方法的时间复杂度降低到O(logn).
假设我们要求a^b的结果,这里我们可以将b转换为二进制来求。例如:
a^11 = a(2 ^ 0 + 2 ^ 1 + 2 ^ 3) = a ^(1011);
所以,我们得出结果:a^11 = (a ^ (2 ^ 3)) *( a ^(2 ^ 1)) *( a^(2 ^ 0));
也就是说,我们只要把次幂化成二进制数,那么我们操作起来就非常的简单了。怎么化成二进制呢?在位运算符中,>>符号表示将一个数字右移一位,也就是说,我们这里可以通过这个符号来一位一位的计算(这里讲的是二进制数,当十进制数使用这个符号来操作的话,我们可以将十进制数当成二进制数右移)。同时我们还可以使用&符号来看看我们二进制数的最后一位数是不是0,比如 a & 1 == 0,表示的是a的二进制数的最后一位是0,反之就是不为0.这里清楚了这一点的话,下面的代码就非常的容易理解。
这里来举一个例子,例如,我们想要求a ^ b的结果,按照快速幂的求法,代码如下:
public int fastPower(int a, int b) {
int ans = 1;
int base = a;
while (b != 0) {
if ((b & 1) != 0) { //如果当前的次幂数最后一位(二进制数)不为0的话,那么我们将当前权值加入到最后答案里面去
ans = ans * base;
}
//权值增加
base = base * base;
b >>= 1;
}
return ans;
}
比如7的二进制为0111 右移一位为0011 即3 所以在这里需要判定是否为奇数若为奇数 则需要*base.