剑指 Offer 16. 数值的整数次方
题目描述
实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。不得使用库函数,同时不需要考虑大数问题。
示例 1:
输入:x = 2.00000, n = 10 输出:1024.00000 示例 2:
输入:x = 2.10000, n = 3 输出:9.26100 示例 3:
输入:x = 2.00000, n = -2 输出:0.25000 解释:2-2 = 1/22 = 1/4 = 0.25
提示:
-100.0 < x < 100.0
-231 <= n <= 231-1
-104 <= xn <= 104
题目分析
考虑几种特殊情况:
- x和n分别为0, 1时,运行程序会不会有bug
- n为负数的时候
Java 代码中 int32 变量 n \in [-2147483648,> 2147483647]n∈[−2147483648,2147483647] ,因此当 n = -2147483648n=−2147483648 时执行 n = -nn=−n 会因越界而赋值出错。解决方法是先将 nn 存入 long 变量 bb ,后面用 bb 操作即可。
最简单的方法是将x循环n次自乘,时间复杂度为O(N)。
需要注意的是n为0的时候, 加一个判断, 结果为1,
你为负数的时候,先将x去倒数,n变成负数,然后再进行循环自乘.
如:
class Solution {
public double myPow(double x, int n) {
if(n == 0){
return 1;
}
if(n < 0){
x = 1/x;
n = -n;
}
double a = x;
for(int i = 0; i < n - 1; i++){
x *= a;
}
return x;
}
}
看上去很完美, 结果:
emm…
快速幂法
顾名思义, 快速幂法可以将时间复杂度降低至O(logn)。从“二进制”和“二分法”两个角度理解快速幂法:
二进制角度
一个数二进制和十进制的转换:
已知一个十进制整数
n
n
n, 其二进制为
m
=
b
m
.
.
.
b
3
b
2
b
1
m = b_m...b_3b_2b_1
m=bm...b3b2b1
一个十进制的数使用二进制各位表示:
n
=
m
=
1
b
1
+
2
b
2
+
.
.
.
+
2
m
−
1
b
m
n = m = 1b_1 + 2b_2 + ... + 2^{m-1}b_m
n=m=1b1+2b2+...+2m−1bm
那想求得的
x
n
x^n
xn就等价于:
x
n
=
x
2
0
b
1
+
2
1
b
2
+
2
2
b
3
+
.
.
.
+
2
m
−
1
b
m
=
x
2
0
b
1
x
2
1
b
2
x
2
2
b
3
.
.
.
x
2
m
−
1
b
m
x^n = x^{2^0b_1+2^1b_2+2^2b_3+...+2^{m-1}b_m} =x^{2^0b_1}x^{2^1b_2}x^{2^2b_3}...x^{2^{m-1}b_m}
xn=x20b1+21b2+22b3+...+2m−1bm=x20b1x21b2x22b3...x2m−1bm
在十进制上求幂=>在二进制上求幂
将式子转换成上面的形式之后, 可以发现,
b
m
b_m
bm只能是1或0,当其为0的时候,式子中这一乘项为1,可以忽略不计。这样就省略了很多计算。
这样一来,计算 x n x^n xn就转化成了解决两个问题:
- 计算
x
2
0
,
x
2
1
,
x
2
2
,
x
2
3
x^{2^0}, x^{2^1}, x^{2^2}, x^{2^3}
x20,x21,x22,x23的值:通过循环操作
x *= x
就可以了; - 判断二进制各位的值是否为1,可以通过“判断最后一位是否为1”+“n向右移动一位”两个操作组成
二分法角度
快速幂法实际上是二分思想的应用:
每次判断尾数是不是1, 就是判断
n
n
n是不是奇数, 如果是奇数, 就将现在的
x
x
x乘到
r
e
s
res
res中
每次右移操作不仅是将二进制的最后一个尾数删除,还相当于将原来的十进制数
n
n
n整除
2
2
2 !
解答
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;
}
}
符合判断条件的时候,res才会发生改变,不符合判断条件则不改变,
而
x
x
x在每一轮循环都会改变,表示的是系数
x
2
i
−
1
x^{2^{i-1}}
x2i−1
参考:
链接:https://leetcode-cn.com/problems/shu-zhi-de-zheng-shu-ci-fang-lcof/solution/mian-shi-ti-16-shu-zhi-de-zheng-shu-ci-fang-kuai-s/