您的位置:首页 > 其它

Leetcode -- Pow(x, n)

2015-01-28 18:10 405 查看
https://oj.leetcode.com/problems/powx-n/

Implement pow(x, n).

public double pow(double x, int n)

问题分析:这题当然不是让你做一个计数器然后一次一次的乘下去。这题有一个test case里n是Integer.MIN_VALUE,乘20多亿次,必然是要超时的。这题的tricky point在于n上,正常来说n也应该是double,但是这里n是一个整型数,所以这题的本质换过来看其实是一个二进制题。

其实这一题换一种简单的说法就是如何用二进制来表达n。理由如下:

res = res时, n = 1, 第一次res *= res时,n = 2,第二次 res *= res时, n = 4,第三次 res *= res时, n = 8....相信你们已经看见规律了。左边是不停的自己乘自己,右边就相当于n = 1 << k

所以我们只需要让这个过程继续下去,我们同时记录 1 << k的k 和对应的res值。直到某个 1 << i 大于 n时,就可以停止了。这个时候我们就可以通过我们已有的k 和对应的res值来拼凑出n所对应的res来了。另外所需要注意的就是是否过界和负数了,另外Integer.MIN_VALUE依旧是要注意的。

给出代码如下:

public double pow(double x, int n) {
if(n == 0)
return 1.0;
boolean isMin = false;
if(n == Integer.MIN_VALUE){
isMin = true;
n += 1;
}
boolean isNeg = n < 0;
n = isNeg ? -n : n;
int two_level = 0;
double res = 1.0;
double[] cached = new double[32];
int counter = 0;
while(n > two_level){
if(two_level << 1 < two_level)
break;
cached[counter] = res;
counter++;
if(two_level == 0){
res = x;
two_level = 1;
}
else{
res *= res;
two_level = two_level << 1;
}
}
int diff = two_level - n;
boolean isDiffNeg = diff < 0;
diff = Math.abs(diff);
while(diff > 0){
if((diff & (1 << counter)) != 0){
diff -= 1 << counter;
res = isDiffNeg ? res * cached[counter + 1] : res / cached[counter + 1];
}
counter--;
}
if(isNeg)
res = 1.0 / res;
if(isMin)
res /= x;
return res;
}


update一下:最近越来越发现上面这个做法很难理解的同时也很冗余。虽然原理基本是正确的。重新做了一次,更新一下代码:

public double pow(double x, int n) {
double result = 1.0;
if(n == Integer.MIN_VALUE){
result *= x;
n++;
}
boolean isNeg = false;
if(n < 0){
isNeg = true;
n = -n;
}
int currentBit = 0;
double cache = x;
double[] cached = new double[32];
while((1 << currentBit) <= n && currentBit < 32){
cached[currentBit] = cache;
cache = cache * cache;
currentBit++;
}
int bit = 0;
while(n != 0){
if((n & (1 << bit)) != 0){
result *= cached[bit];
n = n & (n - 1);
}
bit++;
}
return isNeg ? 1.0 / result : result;
}

前面基本都对,回收所有 1 << x 对应的 pow(cache, 1 << x),然后下一步直接通过二进制来重构n,并且乘以对应的cache就可以了。

2017-12-02 Updated 

经过再一次的思考把cache数组给省掉了,顺便就是一个for loop就搞定了,代码也简洁了些许

public double myPow(double x, int n) {
boolean isNeg = false;
double res = 1.0;
if (n < 0) {
isNeg = true;
if (n == Integer.MIN_VALUE) {
n++;
res *= x;
}
n *= -1;
}
double xCache = 1.0;
for (int i = 0; i < 32 && n != 0; i++) {
xCache = i == 0 ? x : xCache * xCache;
if ((n & (1 << i)) != 0) {
n -= 1 << i;
res *= xCache;
}
}
if (isNeg) res = 1 / res;

return res;
}

不容易啊不容易。囧
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: