原题链接:
http://oj.leetcode.com/problems/powx-n/
这道题是一道数值计算的题目,因为指数是可以使结果变大的运算,所以要注意越界的问题。如同我在 Sqrt(x) 这道题中提到的,一般来说数值计算的题目可以用两种方法来解,一种是以2为基进行位处理的方法,另一种是用二分法。这道题这两种方法都可以解,下面我们分别介绍。
这道题是一道数值计算的题目,因为指数是可以使结果变大的运算,所以要注意越界的问题。如同我在 Sqrt(x) 这道题中提到的,一般来说数值计算的题目可以用两种方法来解,一种是以2为基进行位处理的方法,另一种是用二分法。这道题这两种方法都可以解,下面我们分别介绍。
第一种方法在Divide Two Integers使用过,就是把n看成是以2为基的位构成的,因此每一位是对应x的一个幂数,然后迭代直到n到最高位。比如说第一位对应x,第二位对应x*x,第三位对应x^4,...,第k位对应x^(2^(k-1)),可以看出后面一位对应的数等于前面一位对应数的平方,所以可以进行迭代。因为迭代次数等于n的位数,所以算法的时间复杂度是O(logn)。代码如下:
class Solution {
public:
#define DBL_MAX 1.7976931348623158e+308 /* max value */
#define DBL_MIN 2.2250738585072014e-308 /* min positive value */
double myPow(double x, int n) {
if(n==0) return 1;
int sign=1;
double res=1;
if(n<0)
{
if(x>=1/DBL_MAX||x<=-1/DBL_MAX)
x=1/x;
else
return DBL_MAX;
if(n==INT_MIN)//保证边界值如果n=INT_MIN,让它加1,我要算绝对值得时候能够算。
{
res*=x;
n++;
}
}
n=abs(n);
if(n%2==1&&x<0) sign=-1;
x=abs(x);
while(n>0)
{
if(n%2==1)
{
if(res*x>DBL_MAX) return DBL_MAX;
res*=x;
}
x*=x;
n=n>>1;
}
return sign==1?res:-1*res;
}
};
以上代码中处理了很多边界情况,这也是数值计算题目比较麻烦的地方。比如一开始为了能够求倒数,我们得判断倒数是否越界,后面在求指数的过程中我们也得检查有没有越界。所以一般来说求的时候都先转换为正数,这样可以避免需要双向判断(就是根据符号做两种判断)。
接下来我们介绍二分法的解法,如同我们在Sqrt(x)的方法。不过这道题用递归来解比较容易理解,把x的n次方划分成两个x的n/2次方相乘,然后递归求解子问题,结束条件是n为0返回1。因为是对n进行二分,算法复杂度和上面方法一样,也是O(logn)。代码如下:
class Solution {
public:
double myPow(double x, int n) {
if(n==0) return 1;
if(n<0) return 1.0/powhelp(x,-n);
return powhelp(x,n);
}
double powhelp(double x,int n)
{
if(n==0) return 1;
double res=powhelp(x,n/2);
if(n%2==0)
return res*res;
else
return res*res*x;
}
};