题目地址:
https://leetcode.com/problems/powx-n/
快速幂(exponentiating by squaring)。基本思路是,要求,我们可以先计算,然后再回去求,这类似于分治法,可以降低复杂度。有递归和非递归两种写法。
法1:含递归。由于测试数据里有一个n取Integer.MIN_VALUE
这个样例,而这个值在计算机里是没有相反数的(也就是对于这个数,,不存在其对应的正数),所以要用long来做。代码如下:
public class Solution {
public double myPow(double x, int n) {
return pow(x, n);
}
// 要用long来做
private double pow(double x, long n) {
// base case是n = 0的情况
if (n == 0) {
return 1.0;
}
// 如果n为负,就调整为正数来做。
if (n < 0) {
n = -n;
x = 1.0 / x;
}
// 分治
double half = pow(x, n / 2);
// 根据n的奇偶性来决定要不要额外乘一个x
if (n % 2 == 0) {
return half * half;
} else {
return half * half * x;
}
}
}
时空复杂度。
法2:非递归写法。主要思路是对做二进制展开,然后对这些二进制位从右向左扫描,用一个变量来保存到当前这个二进制位,的那么多次次方的结果是多少。
举个例子来说,如果要算,由于,首先保存的是是多少,也就是,那其实就是。接着开始从右向左扫描,扫描到第位时遇到,就给乘上,同时需要平方一下,这样就保存了这个值,扫描到第位时遇到,保持原样,而继续平方一下,得到了,继续扫描到,这时乘一下,如此下去又乘了,扫描结束。我们统计一下会发现,,正好是所求结果。
代码如下:
public class Solution {
public double myPow(double x, int n) {
return pow(x, n);
}
private double pow(double x, long n) {
if (n < 0) {
n = -n;
x = 1.0 / x;
}
double res = 1.0;
while (n > 0) {
if (n % 2 != 0) {
res *= x;
}
x *= x;
n >>= 1;
}
return res;
}
}
时间复杂度,空间。