1.题目
Implement pow(x, n).
也就是要求实现幂的计算。
2.蛮力法
首先想到的当然是蛮力法,直接乘它个n次:
double myPow(double x, int n) {
for (int i=0;i<n;i++)
{
x*=x;
}
return x;
}
但显然这题当然没那么简单,直接蛮力后果如下:
看来是有时间复杂度要求限制的,蛮力法复杂度是O(n),看来应该是要求O(log(n))(应该不会有常数时间的吧)。
3.二进制方法
把n分解成2进制数,拿10来说吧,分解成
10102
后,表示为
1010=10102=1∗23+0∗22+1∗21+0∗20
分解成二进制数后,n最长为 log2n+1 。
同时还可以做如下分解:
x10=x1∗23+0∗22+1∗21+0∗20=x1∗23∗x0∗22∗x1∗21∗x0∗20=x23∗x21
根据二进制序列各位是否为1,可以分别把 x2i 乘到一起,
Pow(x,n)=Π31i=0n2ix2i
其中 n2i 为n的二进制表示的右起第i位。
x2i+1 可以直接通过 x2i 平方得到,因此这个算法时间复杂度为O(logn)。
需要注意的是当n<0的情况,这种情况下,直接令 x=1x 即可,但不要忘了把n置为正数。
double myPow(double x, int n) {
double r=1;
if (n<0)
{
n=-n;
x=1/x;
}
while (n)
{
if (n&0x1)
r*=x;
x=x*x;
n>>=1;
}
return r;
}
但上面那段代码还是有问题。问题出在了极端情况,n=-2147483648时。
这和计算机用补码表示负数的方法有关系,这个时候,-n=-2147483648,n没法反转成正数,也就出问题了。
至于为什么会这样,我们知道计算机加减运算时是采用补码的方式,所以
−(−2147483648)= ∼0x80000000+0x1=0x8000000=−2147483648
我在这里用了一个小trick,在处理n<0的时候,直接在要返回的结果上除一个x,然后n自加1即可避免这个问题。
double myPow(double x, int n) {
double r=1;
if (n<0)
{
n=-++n;
x=1/x;
r=x;
}
while (n)
{
if (n&0x1)
r*=x;
x=x*x;
n>>=1;
}
return r;
}
Bug真是无处不在,你永远不知道会不会有一个特殊的测试样例会把你的程序搞崩。
记住这个特殊的数,-2147483648。