剑指offer:数值的整数次方

题目描述

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

解题思路

  1. 当底数为0且指数小于0时:会出现对0求倒数的错误情况,可以采用三种错误处理方式的任意一种,可以与面试官讨论决定。
方式优点缺点
返回值和系统API一致不能方便地使用计算结果
全局变量能够方便的使用计算结果用户可能会忘记检查全局变量
异常可以为不同的出错原因定义不同的异常类型,逻辑清晰明了有些语言不支持,抛出异常时对性能有负面影响
  1. 判断double类型底数是否等于0:需要使用近似值来比较
  2. 由于0的0次方在数学上是没有意义的,因此无论输出0还是1都是可以接受的,需要与面试官讨论,表明我们已经考虑到这个边界值了。
  3. 优化求幂函数 
    • 当n为偶数,a^n =(a^n/2)*(a^n/2)
    • 当n为奇数,a^n = a^[(n-1)/2] * a^[(n-1)/2] * a
    • 时间复杂度下降为O(logn)
  4. 使用右移代替除法,用位运算代替求余运算(%),细节优化!
public class Solution {
boolean isVaild = true;
public double Power(double base, int exponent) {
// 需要考虑底数为零且指数为0的特殊情况
if (equals(base, 0.0) && exponent<=0){
isVaild = false;
return 0.0;
}
int absExponent = exponent;
if (exponent < 0)
absExponent = -exponent;
double ret = getPower(base, absExponent);
if (exponent < 0)
ret = 1.0 / ret;
return ret;
}
public double getPower(double base, int exponent){
if (exponent == 0)
return 1.0;
if (exponent == 1)
return base;
// 优化求幂算法,O(logn)
double ret = getPower(base, exponent>>1);
ret = ret*ret;
// 位操作代替求余
if ((exponent&1) == 1)
ret = ret * base;
return ret;
}
// 判断double类型是否为0
public boolean equals(double x, double y){
if(x-y < 0.00001 && x-y > -0.00001)
return true;
else
return false;
}
}

  
我们也可以对上面那个求幂函数转换为二进制进行计算: 
写出指数的二进制表达,例如13表达为二进制1101。 
举例:10^1101 = 10^0001*10^0100*10^1000。 
所以base ^ 13 = (base ^ 1) * (base ^ 4) * (base ^ 8) 
代码如下:

/**
* 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){
// 为1时将该位代表的乘数累乘到最终结果
if((exponent&1)==1)
res*=curr;
curr*=curr;// 2的指数次方翻倍
exponent>>=1;// 右移一位
}
return n>=0?res:(1/res);
}
posted @ 2018-01-09 10:08  小丑进场  阅读(138)  评论(0编辑  收藏  举报