题目
方法一-循环乘
即依次求
x
1
x^1
x1,
x
2
x^2
x2, …,
x
n
−
1
x^{n-1}
xn−1,
x
n
x^n
xn,时间复杂度为
O
(
n
)
O(n)
O(n)
方法二-快速幂
与简单的循环乘相比时间复杂度可以降低至 O ( l o g 2 n ) O(log_2n) O(log2n)
2.1 二进制角度理解快速幂:
设十进制正整数 n 对应二进制数
b
m
.
.
.
b
3
b
2
b
1
b_m...b_3b_2b_1
bm...b3b2b1,则有
n
=
1
b
1
+
2
b
2
+
2
2
b
3
+
.
.
.
+
2
m
−
1
b
m
n=1b_1+2b_2+2^2b_3+...+2^{m-1}b_m
n=1b1+2b2+22b3+...+2m−1bm
x
n
=
x
1
b
1
⋅
x
2
b
2
⋅
x
2
2
b
3
⋅
.
.
.
⋅
x
2
m
−
1
b
m
x^n=x^{1b_1}\cdot x^{2b_2}\cdot x^{2^2b_3}\cdot...\cdot x^{2^{m-1}b_m}
xn=x1b1⋅x2b2⋅x22b3⋅...⋅x2m−1bm
所以原问题转化为解决以下两个问题:
- 计算 x 1 , x 2 , x 4 , . . . x 2 m − 1 x^1, x^2,x^4,...x^{2^{m-1}} x1,x2,x4,...x2m−1的值
- 获取 b 1 , b 2 , b 3 , . . . , b m b_1,b_2,b_3,...,b_m b1,b2,b3,...,bm的值:循环执行【判断最右一位是否为1】和【右移一位】操作。
循环计算 x 2 i − 1 b i x^{2^{i-1}b_i} x2i−1bi的值并累乘即可得到最终结果。
- 当 b i = 0 b_i=0 bi=0时, x 2 i − 1 b i = 1 x^{2^{i-1}b_i}=1 x2i−1bi=1
- 当 b i = 1 b_i=1 bi=1时, x 2 i − 1 b i = x 2 i − 1 x^{2^{i-1}b_i}=x^{2^{i-1}} x2i−1bi=x2i−1
2.2 二分法角度理解快速幂:
二分推导: x n = ( x 2 ) n / 2 x^n=(x^2)^{n/2} xn=(x2)n/2,需要区分奇偶两种情况:
- 当 a 为偶数时, x n = ( x 2 ) ⌊ n / 2 ⌋ x^n=(x^2)^{\left \lfloor n/2\right \rfloor} xn=(x2)⌊n/2⌋;
- 当a 为奇数时, x n = x ⋅ ( x 2 ) ⌊ n / 2 ⌋ x^n=x\cdot (x^2)^{\left \lfloor n/2\right \rfloor} xn=x⋅(x2)⌊n/2⌋
快速幂算法流程:
- 当 x = 0 x=0 x=0时,直接返回0
- 初始化 r e s = 1 res=1 res=1
- 当 n < 0 n<0 n<0时,将问题转到 n ≥ 0 n\geq 0 n≥0范围内:令 x = 1 / x , n = − n x=1/x,\ n=-n x=1/x, n=−n
- 循环计算,
n
=
0
n=0
n=0 时跳出循环
当二进制最右一位是1(即 n & 1 = 1 n\And 1=1 n&1=1)时:执行 r e s ∗ = x res\ *\!=\ x res ∗= x;
执行 x ∗ = x x\ *\!=\ x x ∗= x;
执行 n 右移一位,即 n > > = 1 n\ >>\!=\ 1 n >>= 1 - 返回 r e s res res
注意:
- int32的范围为 [ − 2 31 , 2 31 − 1 ] \left[-2^{31},\ 2^{31}-1 \right] [−231, 231−1],所以当 n = − 2 31 n=-2^{31} n=−231 时直接执行 n = − n n=-n n=−n 会越界,所以应该先将 n 转为 long 型
- 当 n < 0 n<0 n<0时,将问题转到 n ≥ 0 n\geq 0 n≥0范围内这一步里,b 应该用 -b 赋值而非 -n,因为当 n = − 2 31 n=-2^{31} n=−231 时 -n 就已经越界了表示不了了
代码:
class Solution {
public double myPow(double x, int n) {
if(x == 0)return 0;
long b = n;
double res = 1.0;
if(b < 0){
x = 1 / x;
b = - b;
}
while(b > 0){
if((b & 1) == 1)res *= x;
x *= x;
b >>= 1;
}
return res;
}
}
复杂度分析:
- 时间复杂度: O ( l o g 2 n ) O(log_2n) O(log2n)
- 空间复杂度: O ( 1 ) O(1) O(1)