50. Pow(x, n)
昨天溜出去玩了,没写题,今天看有时间的话补上吧,先说今天的题
题目 :实现 pow(x, n) ,即计算 x 的 n 次幂函数。
示例 1:
输入: 2.00000, 10
输出: 1024.00000
示例 2:
输入: 2.10000, 3
输出: 9.26100
示例 3:
输入: 2.00000, -2
输出: 0.25000
解释: 2-2 = 1/22 = 1/4 = 0.25
说明:
-100.0 < x < 100.0
n 是 32 位有符号整数,其数值范围是 [−2^31, 2^31 − 1] 。
其实就是要求实现pow() 函数 这里蛮力法是通不过的
未通过的测试样例
2.00000
-2147483648
蛮力法时间复杂度为O(n) 因此需要O(nlogn)级别的算法
//蛮力法
class Solution {
public:
double myPow(double x, int n) {
if(x==1||n==0) return 1;
if(n<0) {x=1.0/ x;n=-n;}
double res=x;
for(long i=1;i<n;i++)
{
res=res*x;
}
return res;
}
};
这里首当其冲的就是二分快速幂运算
譬如当我们计算 2^10 可以分解为 两个2^5相乘
而2^5 又可以分解为两个2^2相乘再乘一个2
就可以极大缩减计算量
同时需要注意一个小坑:
因为我们计算负次幂时 利用 x^(-y)= (1/x)^y
所以存在n由负转正,但题目说n 是 32 位有符号整数,其数值范围是 [−2^31, 2^31 − 1]
转正有可能溢出,所以需要借助long型作为辅助
这里是递归二分运算代码
注意我标注的地方:不能写成getres(x,mid)乘getres(x,mid)
否则相当于两次递归 还是O(N)级别
class Solution {
public:
double getres(double x,long N)
{
if(N==1) return x;
long mid=N/2;
if(N%2==0)
{
double half=getres(x,mid); //不能写成getres(x,mid)*getres(x,mid);
return half*half;
}
else
{
double half=getres(x,mid);
return x*half*half;
}
}
double myPow(double x, int n) {
if(x==1||n==0) return 1;
long N=n;
if(N<0) return getres(1.0/ x, -N);
return getres(x,N);
}
};
也可以进一步思考
譬如当我们计算 2^10
10的二进制是1010 所以我们可以分解为 2的2^1乘 2的 2^3
也就是说2^10 =4乘256=1024
当二进制位为1时 res*=x;
每次执行 x*=x,二进制右移一位
class Solution {
public:
double myPow(double x, int n) {
if(x == 1 || n == 0) return 1;
double ans = 1;
long num = n;
if(n < 0){
num = -num;
x = 1/x;
}
while(num){
if(num & 1) ans *= x;
x *= x;
num >>= 1;
}
return ans;
}
};