题目
难度
力扣难度中等,实际难度中等
分类
快速幂|二分法
思路
二分法
这道题,最差的情况就是单循环,x * x * x....... 乘n遍,但是面试算法题就是最简单的方法一定会GG。 目前的时间复杂度是n,进一步优化一定是logn 所以第一时间想到的就是递归二分法,把x相乘的步骤对半砍
- x^16,
- 砍成x^8 * x^8,
- 砍成x^4 * x^4 * x^8
- 砍成x^2 * x^2 * x^4 * x^8
- 砍成x * x * x^2 * x^4 * x^8
每一轮 只需要算一次
x*x=x^2和x^2 * x^2 = x^4与x^4 * x^4 = x^8与x^8 * x^8 = x^16结果就出来了
这个算法如果是奇数的话需要再*x 如果是负数边界值一定要先/2再取反,因为负数边界值比整数大一,所以直接取反翻不过来
二进制快速幂
这个和上面那个时间复杂度一样但是在计算机层面的计算会更快
大概的意思就是把n拆成二进制,然后根据二进制的1和0决定要不要把x^(2^(1,2,3,4...))乘起来,换句话说就是x^1,x^2,x^4,x^8,x^16.....
比如n = 11 二进制是1101 那么相当于 res = x^1 * x^4 * x^8 只把1,4,8的三项乘起来就是x^11
- 直接做位运算可以把n看成二进制不需要进行转换
- n&1表示当前位是否是1
- 这里的n>>1表示计算下一位
注意
需要注意n可能为负数需要对x做一次 x = 1/x处理
代码
递归实现的二分法
class Solution {
public double myPow(double x, int n) {
if (n == 0) {
return 1;
}
if (n > 0) {
double temp = myPow(x, n / 2);
if (n % 2 == 0) {
return temp * temp;
} else {
return temp * temp * x;
}
} else {
double temp = myPow(1 / x, -(n / 2));
if (n % 2 == 0) {
return temp * temp;
} else {
return temp * temp * 1/ x;
}
}
}
}
二进制快速幂
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;
}
}