题目
实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。不得使用库函数,同时不需要考虑大数问题。
思路
快速幂算法
求 x^n
最简单的方法是通过循环将 n
个 x
乘起来,依次求 x1,x2,...,x^n
,时间复杂度为 O(n)
。 快速幂法 可将时间复杂度降低至 O(logn)
,当指数 n
为负数时,可以计算 x^-n
再取倒数得到结果,因只需要考虑 n
为自然数的情况。
快速幂 + 递归
快速幂算法 的本质是分治算法。
举个例子,如果要计算 x ^ 64
,可以按照:
的顺序,从 x
开始,每次直接把上一次的结果进行平方,计算 6
次就可以得到 x^64
的值,而不需要对 x
乘 63
次 x
再举一个例子,如果要计算 x^77
,可以按照:
的顺序,可以看到有的步骤是直接平方得来的,有的步骤在平方后还需要乘一个x
,如x^4 → x^9
直接从左到右进行推导很难看出来,在将上一次的结果平方之后,还需不需要额外乘 x
。
但如果从右往左看,并采用分治的思想:
- 当要计算
x^n
时,可以先递归地计算出y=x^⌊n/2⌋
,其中⌊a⌋
表示对a
进行下取整; - 根据递归计算的结果,如果
n
为偶数,那么x^n = y^2
;如果n
为奇数,那么x^n = y^2 * x
- 递归的边界为
n=0
,任意数的0
次方均为1
。
由于每次递归都会使得指数减少一半,因此递归的层数为 O(logn)
java代码如下:
class Solution{
public double myPow(double x, int n){
//将n用long表示,因为正值和负值的取值范围不是对称的,INT_MIN = -INT_MAX - 1,假如n是INT_MIN,那么-n==INT_MAX + 1, 超出了INT_MAX的表示范围了。
long N = n;
//如果N为正数,直接计算,如果N为负数,则计算x^-n的倒数
return N >= 0 ? quickMul(x,N) : 1.0 / quickMul(x,-N);
}
public double quickMul(double x, long N){
if(N == 0){
return 1.0;
}
double y = quickMul(x, N / 2);
//如果N偶数,直接x^n == y ^ 2,如果N是奇数,则多乘一个x
return N % 2 == 0 ? y * y : y * y * x;
}
}