实现 pow(x, n) ,即计算 x 的 n 次幂函数。
示例 1:
输入: 2.00000, 10
输出: 1024.00000
示例 2:
输入: 2.10000, 3
输出: 9.26100
示例 3:
输入: 2.00000, -2
输出: 0.25000
解释: 2-2 = 1/22 = 1/4 = 0.25
说明:
-100.0 < x < 100.0
n 是 32 位有符号整数,其数值范围是 [−231, 231 − 1] 。
解题思路:
暴力:根据幂次,将底数自乘幂次(n次),循环得到结果,负数指数也只是正数结果分之一,这种方法不用想就知道肯定超时的
改进暴力:折半计算,当指数为偶数(n %20)时,就是(x^n = x ^{(n/2)^2}) ,如求2的8次幂,就等于2的4次幂的平方,而2的4次幂有等于2的2次幂的平方,2的2次幂有等于2的一次幂的平方,2的一次幂就等于2的0次幂的平方再乘与2也就是2本身;当指数为奇数时(n % 21),除了上述的平方外,还需要再乘一次底数x
通过折半计算,每次把n减半,降低了空间复杂度,也降低了时间复杂度
class Solution {
public:
double myPow(double x, int n) {
double res = 1.0;
for(int i = n; i != 0; i /= 2){
if(i % 2 != 0){
res *= x;
}
x *= x;
}
return n < 0 ? 1 / res : res;
}
};
快速幂+递归
快速幂算法」的本质是分治算法。举个例子,如果我们要计算 (x^{64}),我们可以按照:
的顺序,从 xx 开始,每次直接把上一次的结果进行平方,计算 66 次就可以得到 (x^{64})的值,而不需要对 x乘 63次 x。
再举一个例子,如果我们要计算 (x^{77}),我们可以按照:
的顺序,在(x o x^2,x^2 o x^4,x^19 o x^38)这些步骤中,我们直接把上一次的结果进行平方,而在 (x^4 o x^9,x^9 o x^19,x^38 o x^7)这些步骤中,我们把上一次的结果进行平方后,还要额外乘一个x。
直接从左到右进行推导看上去很困难,因为在每一步中,我们不知道在将上一次的结果平方之后,还需不需要额外乘 xx。但如果我们从右往左看,分治的思想就十分明显了:
- 当我们要计算(x^n时,我们可以先递归地计算出 y = x^{lfloor n/2 floor},其中 lfloor a floor 表示对 a 进行下取整;)
- (根据递归计算的结果,如果 n 为偶数,那么 x^n = y^2;如果 n 为奇数,那么 x^n = y^2 * x)
- 递归的边界为 n = 0n=0,任意数的 00 次方均为 1
class Solution {
public:
double quickMul(double x,long long N)
{
if(N == 0)
return 1.0;
double y = quickMul(x,N/2);
return N % 2 == 0?y*y:y*y*x;
}
double myPow(double x, int n) {
long long N = n;
return N >= 0?quickMul(x,N):1.0/quickMul(x,-N);
}
};