题目
Leetcode 50. Pow(x,n)
实现 pow(x, n) ,即计算 x 的 n 次幂函数(x^n)
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/powx-n
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解析
拿到手直接
class Solution {
public:
double myPow(double x, int n) {
return pow(x,n);
}
};
调cmath里的pow方法。就AC了
不过这道题本意应该是要自己写方法
最直接的思路仅仅考虑实现,通过次数循环控制x自乘即可。这是v1版本
考虑到大量的for费时又费力
想想这道题是要求幂次,可以通过二进制移位方式来实现。可以写出v2版本代码
再想想可以通过缩小规模来实现,这是v3代码
实现
暴力求解 v1
class Solution {
public:
double myPow(double x, int n) {
long long N=n;
if(N<0){
x=1/x;
N=-N;
}
double ans=1;
for(long long i=0;i<N;i++)ans*=x;
return ans;
}
};
时间复杂度O(n)
空间复杂度O(1)
结果是没错,不过不出意外的,超出了时间限制。
按位移动法 v2
注意,起初的思路是通过对x进行按n进行移位操作,后来发现C++中的移位操作只能对int操作。也就是可以对整数实现pow,对带有小数的会失败。还是把代码放出来供参考
class Solution {
public:
double myPow(double x, int n) {//失败,仅对整数可以实现求幂次,带小数结果错误
if(n==0)return 1;
if(n==1)return x;
int res=(int)x;
res<<=abs(n)-1;
return n>0?(double)res:(1/(double)res);
}
通过对计算次数减少,也就是对幂次n进行移位。可以大幅减少运算次数,并且成功AC。代码如下
class Solution {
public:
double myPow(double x, int n) {
if(n==0)return 1;
if(n==1)return x;
if(n==-1)return 1/x;
if(n&1){
return myPow(x*x,n>>1)*x;
}
return myPow(x*x,n>>1);
}
};
二分思想v3
采用分治法,通过二分法实现O(log n)的时空复杂度
class Solution {
public:
double f(double x,int n){
if(n==0)return 1;
double half=f(x,n/2);
return n&1==1?half*half*x:half*half;
}
double myPow(double x, int n) {
if(n==0||x==1)return 1;
long long N=n;
return N>0 ? f(x,N): 1/ f(x,-N);
}
};
迭代
妙在对幂转了2进制,从最后一位开始判断是否有做出贡献,如2^16次方。
如x^77次方,77的二进制形式对应了(1001101)中的每个1。
2^0=1
2^2=4
2^3=8
2^6=64
把这些幂次相加等于77
这里来个例子,比如x=2,n=16。指数16可以拆分为2^4次方,二进制表示形式就是(10000),程序过程如下图所示
class Solution {
public:
double ff(double x,long long n){
double x_useful=x;
double ans=1;
while(n>0){
if(n&1){
//末位是1
ans*=x_useful;
}
x_useful*=x_useful;
n/=2;
}
return ans;
}
double myPow(double x, int n) {
long long N=n;
return N>=0? ff(x,N):1/ff(x,-N);
}
};
时间复杂度:O(logn)
空间复杂度:O(1)