[leetcode] #50 Pow(x,n)

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=123+022+121+020

分解成二进制数后,n最长为 log2n+1

同时还可以做如下分解:

x10=x123+022+121+020=x123x022x121x020=x23x21

根据二进制序列各位是否为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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值