这题顾名思义,要求实现double x的n次方,当然n可正可负。
上路想都不想觉得太简单了然后唰唰唰写了一个最无脑直接分递归版本:
//version 1.0
class Solution {
public:
double pow(double x, int n) {
if(n==0)
return 1.0;
if(n>0)
return x*pow(x,n-1);
if(n>0)
return (1/x)*pow(x,n+1);
}
};
结果显示:
Time Limit Exceeded. Last executed input:0.00001, 2147483647
。。。。。。
仔细一看才发现是由于这种递归时间复杂度为O(n),所以当n非常大的时候,时间会线性增加然后导致出现这种error。
这时候又是上网一同乱搜发现主流的解决方法是用二分法[1]:
xn = xn/2 * xn/2 * xn%2
这种算法的时间复杂度为O(logN),明显要比O(N)好多了。
于是唰唰唰又写了一个版本:
//version 2.0
class Solution {
public:
double pow(double x, int n) {
if(n==0)
return 1;
if(n==1)
return x;
if(n==-1)
return 1/x;
if(n>0)
return pow(x,n/2)*pow(x,n/2)*pow(x,n%2);
if(n<0)
return pow(x,n/2)*pow(x,n/2)*pow(x,n%2);
}
};
结果显示:
Time Limit Exceeded. Last executed input:0.00001, 2147483647
。。。
.。。。WTF!!!
后来找到一个也是二分法的版本[2]后才发现问题,在version2.0中每次return都要算两次pow(x,n/2),这样其实复杂度为
O(2*logN),对于超大的N还是超时了。
然后简单用了一个临时变量tmp解决了问题:
//version 3.0
class Solution {
public:
double pow(double x, int n) {
if(n==0)
return 1;
if(n==1)
return x;
double tmp=pow(x,abs(n/2));
if(n>0)
return tmp*tmp*pow(x,n%2);
if(n<0)
return 1/(tmp*tmp*pow(x,abs(n)%2));
}
};
Submission Result: Accepted (20ms)
小结(貌似第一次用这么正式的小结啊,不过感觉这道理训练的意义很大)
第一:看起来简单的题目其实不一定简单,容易犯想当然的低级错误;
第二:算法的重要性,一个好的算法要比一个普通的算法(两个都是正确的)效率要高很多很多;
第三:细节很重要,一个不小心忽略了细小的地方很有可能会导致结果的巨大差距。
参考:
[1] http://blog.unieagle.net/2012/08/23/leetcode%E9%A2%98%E7%9B%AE%EF%BC%9Apowxn/
[2] http://blog.youkuaiyun.com/havenoidea/article/details/12853985