LeetCode :: Pow(x, n)

来源:互联网 发布:企业数据防泄密体系 编辑:程序博客网 时间:2024/06/05 06:18

题目要求很简洁,Implement pow(x, n),没了。

函数的原型是这样的:double pow(double x, int n) ;

一、这里最容易想到的,肯定是时间复杂度为O(N), 利用一个递归,我试了一下,果然和想的一样 TL。

二、把pow分解为 pow(x, n / 2) ,T(N) = T(N / 2) + O (1),这里的时间复杂度利用master method,显而易见是O(logN)

#include <iostream>using namespace std;double pow(double x, int n) {        double result = 1, tmp;        if (n == 0) return 1;        if (n > 0){            tmp = pow(x, n / 2);            if (n % 2){                result = tmp * tmp * x;            }            else{                result = tmp * tmp;            }        }        else{            tmp = pow(x, -n);            result = 1 / tmp;        }        return result;   }int main(){    double x;    int n;    cin >> x >> n;    cout << pow (x , n);}

这个代码是有错误的代码,SUMBIT的时候,提示了Runtime error,通不过的case是 1.00000, -2147483648

这里有个值得注意的地方,这个-2147483648是32位带符号整型的最小值,这里展开说一下。

首先更正一个经常性的教科书错误,补码是什么?怎么去得到?我以前的第一反应是原码取反加1,我们考虑一下-128,假设是一个8位存放,那么它的原码是什么?你根本找不到,因为溢出了。其实,机器里面,根本就是一个完全的补码存放,补码计算的机制,这个所谓的原码只是方便我们记忆而已。

好,然后考虑这个边界问题。

问题1:int -2147483648 ;编译后的值正确吗?

上面说的转换程序,这个编译的步骤为: 计算2*10^9 + 2*10^8+ …… +4*10+8 ,因为int只能表示到 2147483647 (0x7fff ffff),再加1的话就溢出了,得到了:0×8000 0000 ,(就是 -2147483648) ,然后再把这个结果与 -1 就是 0xffff ffff 相乘,得到的结果也溢出了,为:0×8000 0000 ,但是这恰好是 – 2147483648的补码,所以,虽然编译中虽然出现了两次溢出,但得到的结果是正确的。

问题2:int x = – 2147483648; 那么 –x 是 2147483648吗?

因为 – 2147483648 (0×8000 0000)与-1 (0xfff ffff)相乘结果为:0×8000 0000 就是– 2147483648 ,所以 –x 的结果还是 – 2147483648 而不是2147483648 。   所以,凡是结果可能超越表示范围的时候,一定要慎重,因为结果可能是你意料之外的

PS: 上面的两个问题我是从http://moper.me/summary-points-of-four-code-conversion-2.html里面摘抄的,如果原作者看到,请原谅我冒昧,没经过同意。

里就是出现了Runtime error的根本原因了,n = -– 2147483648, -n 也是 这个值,根本不会改变,然后我之前的代码那样的话,就一直陷入了那个n < 0的怪圈里面的了,然后就没有然后了,Runtime error。改之。

double pow(double x, int n) {        double result = 1, tmp;        if (n == 0) return 1;        tmp = pow(x, abs(n / 2));    //这里用abs把负数取正,由于除以2之后,就不会在边界了。        if (n > 0){            if (n % 2){                result = tmp * tmp * x;            }            else{                result = tmp * tmp;            }        }        else{              if (n & 1)                return 1.0 / (tmp * tmp * x);                else                 return 1.0 / (tmp * tmp);        }        return result;   }

三、这里再介绍一个很有趣的方法也是logN的时间复杂度,但是它用到了一个移位的思想,下面是LeetCode网站上外国小伙在discuss中给出的思路。

Consider the binary representation of n. For example, if it is "10001011", then x^n = x^(1+2+8+128) = x^1 * x^2 * x^8 * x^128. Thus, we don't want to loop n times to calculate x^n. To speed up, we loop through each bit, if the i-th bit is 1, then we add x^(1 << i) to the result. Since (1 << i) is a power of 2, x^(1<<(i+1)) = square(x^(1<<i)). The loop executes for a maximum of log(n) times.

然后写了一下代码,这里利用了不同的对于边界值的处理方法。随便提一下,想要用到INT_MAX之类的定义好的常量应该包含头文件 climts 。

class Solution {public:    double pow(double x, int n) {        // Start typing your C/C++ solution below        // DO NOT write int main() function        if(n<0){if(n==INT_MIN)return 1.0 / (pow(x,INT_MAX)*x);elsereturn 1.0 / pow(x,-n);}        if(n==0)            return 1.0;double ans = 1.0 ;for(;n>0; x *= x, n>>=1){if(n&1>0)ans *= x;}return ans;    }};

第一篇完了,废话有点多,如果有大神看了,感觉我哪里说的有问题,还希望大神们指出。





2 0
原创粉丝点击