50. Pow(x, n)
✨核心逻辑
本题采用 快速幂(二进制指数法 / 折半计算) 的策略:
- 边界处理与负数幂:如果指数
n是负数,则需要将底数x变为其倒数1/x,同时将指数变为正数。这里必须将n赋值给一个long类型变量N,因为n = -2147483648(Integer.MIN_VALUE)取反时会超出int的最大正数范围导致溢出。 - 二进制展开:将指数
N看作二进制数(例如N = 13,二进制为1101,代表8 + 4 + 1)。我们可以通过循环不断将指数N右移(N >> 1)来遍历它的二进制位。 - 按位乘入:在每次循环中,判断当前指数
N的最低位(N & 1)是否为1。如果为1,则将当前的底数x乘入最终结果result中。 - 底数自乘:无论最低位是什么,每次循环都要将底数
x进行平方处理x = x * x(即x^2,x^4,x^8...),以便在下一次循环中的按位判断使用时,能一次性累乘进去。
🔥代码实现(含详细变量注释)
class Solution {
public double myPow(double x, int n) {
// N:将传入的 int 型指数 n 转为 long 类型。
// 必须转成 long,是因为当 n = Integer.MIN_VALUE(-2147483648)时,取反操作 `-n` 会超出 int 的取值范围产生溢出。
long N = n;
// 如果指数是负数,将底数变为倒数,并将指数转为正数
if (N < 0) {
x = 1 / x;
N = -N;
}
// result:用于记录最终计算的幂次结果,初始化为 1.0
double result = 1.0;
// 快速幂核心循环:只要指数 N 大于 0 就继续运算
while (N > 0) {
// 判断 N 的当前二进制最低位是否为 1(即 N 是否为奇数)
// 如果为 1,则将当前累积的底数 x 乘入 result 中
if ((N & 1) == 1) {
result *= x;
}
// 底数 x 每轮循环都要自乘(平方),形成 x^1, x^2, x^4, x^8... 的序列
x = x * x;
// 指数 N 向右无符号移动 1 位(相当于除以 2,舍弃最低位)
N >>= 1;
}
// 返回最终计算出来的幂运算结果
return result;
}
}
- ⏱️复杂度分析
时间复杂度:O(log N),其中 N 是指数。循环执行的次数等于指数 N 的二进制位数,即为 log_2 N,比暴力循环的 O(N) 算法快得多。
空间复杂度:O(1),仅使用了 N、result 和循环控制变量等常数个额外空间。
🔍总结一下:
这道题无法暴力,2的32次方-1要执行21多亿次,直接超时
可将n转化为二进制,比如10:1010,每位对应的二进制值是8421,也就是x的8次方 × x的2次方,对x不断平方就能得到对应位置的x的多少次方,然后逐次右移N,判断末尾是否为1,是则累乘到结果中即可