新年好!
突然发现,上一次做算法题已经是一个月前了。虽然每天做一题可能也不会花费很多时间,但是确实很难坚持一段比较长的时间。特意挑选了一个简单一些的题目开始这一年,希望今年每天1题的目标可以有比较高的完成度吧。
题目
实现 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
思路
这是一个快速幂的题目,如果真的做n次乘法,肯定会TLE。
所以,我们优化的核心是怎么减少计算的次数,即减少时间复杂度。
首先,由幂的性质我们知道,如果n可以拆分成数a和b的和,即n=a+b,那么pow(x,n) = pow(x,a) * pow(x,b)。因为我们要尽量减少计算的次数,所以希望pow(x,a) = pow(x,b) = pow(x,n/2),这样我们计算得到pow(x,a)可以被充分利用。
顺着上面的思路,我们可以想到递归的方法:如果n是偶数,pow(x,n) = pow(x,n/2)pow(x,n/2);如果n是奇数,pow(x,n) = pow(x,n/2)pow(x,n/2)x;通过递归的方式计算出结果。
另外一个思路是,把n转换成2进制的形式,n = b0pow(2,0) + b1pow(2,1) +...+ bmpow(2,m),其中,bk归属于(0,1)。这样,我们就从x的0次方(m=0)开始,不断去计算x的pow(2,m)次幂作为temp,如果n转成的2进制数这1位是1,结果就乘以temp。
例如 x = 3, n = 5的情况:
n = 5 = (101)b
= *
所以,我们可以在计算、、的过程中,选择二进制对应位数上是1的进行相乘得到结果。
当然,计算temp和判断当前是否要乘以temp可以在一个循环里面进行,通过 n && 1结果是否是1来判断当前n转换成2进制后的最后一位是否1来判断是否要乘以temp,然后通过 n >> 1的方式,将n右移一位来遍历n的二进制每一位。
Java版本代码
class Solution {
public double myPow(double x, int n) {
if (x == 0) {
return 0;
}
// 为了保证-n不溢出,先转换成long类型
long power = n;
// n是负数时,先转换成正数的情况
if (power < 0) {
x = 1 / x;
power = -power;
}
double result = 1.0;
double temp = x;
while (power > 0) {
if ((power & 1) == 1) {
result *= temp;
}
temp *= temp;
power = power >> 1;
}
return result;
}
}