1.题目描述
实现 pow(x, n) ,即计算 x 的 n 次幂函数。
示例 1:
示例 2:
示例 3:
说明:
1.-100.0 < x < 100.0
2.n 是 32 位有符号整数,其数值范围是 [−231, 231 − 1] 。
2.快速幂+递归
「快速幂算法」的本质是分治算法。举个例子,如果我们要计算
x
64
x^{64}
x64,我们可以按照:
x
→
x
2
→
x
4
→
x
8
→
x
16
→
x
32
→
x
64
x \to x^2 \to x^4 \to x^8 \to x^{16} \to x^{32} \to x^{64}
x→x2→x4→x8→x16→x32→x64
的顺序,从 x 开始,每次直接把上一次的结果进行平方,计算 6 次就可以得到
x
64
x^{64}
x64的值,而不需要对 x 乘 63 次 x。再举一个例子,如果我们要计算
x
77
x^{77}
x77 我们可以按照:
x
→
x
2
→
x
4
→
x
9
→
x
1
9
→
x
3
8
→
x
77
x \to x^2 \to x^4 \to x^9 \to x^19 \to x^38 \to x^{77}
x→x2→x4→x9→x19→x38→x77
的顺序,在
x
→
x
2
,
x
2
→
x
4
→
,
x
19
→
x
38
x \to x^2,x^2 \to x^4 \to,x^{19} \to x^{38}
x→x2,x2→x4→,x19→x38
这些步骤中,我们直接把上一次的结果进行平方,而在
x
4
→
x
9
,
x
9
→
x
19
,
x
38
→
x
77
x^4 \to x^9,x^9 \to x^{19},x^{38} \to x^{77}
x4→x9,x9→x19,x38→x77
这些步骤中,我们把上一次的结果进行平方后,还要额外乘一个 x。
直接从左到右进行推导看上去很困难,因为在每一步中,我们不知道在将上一次的结果平方之后,还需不需要额外乘 x。但如果我们从右往左看,分治的思想就十分明显了:
当我们要计算
x
n
x^n
xn 时,我们可以先递归地计算出
y
=
x
⌊
n
/
2
⌋
y = x^{\lfloor n/2 \rfloor}
y=x⌊n/2⌋,其中
⌊
a
⌋
\lfloor a \rfloor
⌊a⌋表示对 a 进行下取整;根据递归计算的结果,如果
n
n
n 为偶数,那么
x
n
=
y
2
x^n = y^2
xn=y2;如果 n 为奇数,那么
x
n
=
y
2
∗
x
x^n = y^2 * x
xn=y2∗x;递归的边界为
n
=
0
n = 0
n=0,任意数的 0 次方均为 1。
3.代码
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);
}
};
4.复杂度分析
时间复杂度:O(logn),即为递归的层数。
空间复杂度:O(logn),即为递归的层数。这是由于递归的函数调用会使用栈空间。
5.快速幂+迭代
每个额外乘的 x 在之后都会被平方若干次。而这些指数 1,4,8 和 64,恰好就对应了 77 的二进制表示
(
1001101
)
2
(1001101)_2
(1001101)2中的每个 1!
这样以来,我们从 x 开始不断地进行平方,得到
x
2
,
x
4
,
x
8
,
x
16
,
⋯
x^2, x^4, x^8, x^{16}, \cdots
x2,x4,x8,x16,⋯如果 n 的第 k 个(从右往左,从 0 开始计数)二进制位为 1,那么我们就将对应的贡献
x
2
k
x^{2^k}
x2k计入答案。
6.代码
class Solution {
public:
double quickMul(double x, long long N){
double res = 1.0;
double x_contribute = x;
while(N > 0){
//如果二进制最后一位为1
if(N % 2 == 1){
res *= x_contribute;
}
x_contribute *= x_contribute;
N /= 2;
}
return res;
}
double myPow(double x, int n) {
long long N = n;
return N >= 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N);
}
};
7.复杂度分析
时间复杂度:O(logn),即为对 n 进行二进制拆分的时间复杂度。
空间复杂度:O(1)。