50. Pow(x, n)
Leetcode Math Binary Search题目¶
Implement \text{pow}(x, n), which calculates x raised to the power n(x^n).
Example 1:
Input: 2.00000, 10
Output: 1024.00000
Example 2:
Input: 2.10000, 3
Output: 9.26100
Example 3:
Input: 2.00000, -2
Output: 0.25000
Explanation: 2-2 = 1/22 = 1/4 = 0.25
Note:
- -100.0 < x < 100.0
- n is a 32-bit signed integer, within the range [−2^{31}, 2^{31} − 1]
分析¶
最直接的方式当然是O(n)的算法,将x乘以或者除以n次,
double myPow(double x, int n) {
if (x == 0) return x;
x = x > 0 ? x : 1.0/x;
double res = x;
for (int i = 1; i < n; i++) res *= x;
return res;
}
可惜的这种方法超时了,稍微想一想就知道当n很大的时候,这种解法肯定是不行的。
另一种方法是使用分治算法,在这里,分治算法的递归公式为
x^n = x^{(n/2)} \times x^{(n/2)} \times x^{(n\%2)}
最差运行时间T(n)用递归表达式表达为
T(n) = T(n/2)\times T(n/2) \times T(n\%2)
因为n/2和n%2的最终结果只有0,-1,1三种,所以只考虑这三种base case.
public double myPow(double x, int n) {
if (n == 0) return 1;
if (n == 1) return x;
if (n == -1) return 1.0 / x;
double y = myPow(x, n / 2);
return y * y * myPow(x, n % 2);
}
下面用位操作来计算。考虑n的二进制表示. 例如, 如果n是 "10001011", 则 x^n = x^{1+2+8+128} = x^{1} \times x^{2} \times x^{8} \times x^{128}. 因此, 我们不用循环n次来计算x^n. 为了加快计算, 我们遍历n中的每一位, 如果第i位是1, 我们把结果乘以x^{2^i} = x^{(1 << i)}. 既然 (1 << i)是2的指数, x^{(1<<(i+1))} = square(x^{(1<<i)}). 这个循环最多执行\log(n)次, i.e.n的二进制表示中最多有\log(n)-1位1).
public double myPow(double x, int n) {
if (n == 0) return 1;
if (n == 1) return x;
if (n < 0) {
// 不能直接 n = -n, 当n = -2147483648
if (n == Integer.MIN_VALUE) {
return 1 / myPow(x, Integer.MAX_VALUE) / x;
} else {
x = 1.0/x;
n = -n; //防止溢出
}
}
double res = 1;
while (n > 0) {
// n的第i位是1
if ((n & 1) > 0)
// res *= x^(1 << i)
res *= x;
// n 右移一位
n >>= 1;
x = x*x;
}
return res;
}