Pow [source code]

public class Pow {
static
/******************************************************************************/
class Solution {
    public double myPow(double x, int _n) {
        int n = _n;
        if (n < 0) {
            x = 1 / x;
            n = -n;
        }
        double A = 1.0;
        char[] bits = Integer.toBinaryString (n).toCharArray ();
        for (int i = 0; i < bits.length; i++) {
            A *= A;
            if (bits[i] == '1')
                A *= x;
        }
        return A;
    }
}
/******************************************************************************/

    public static void main(String[] args) {
        Pow.Solution tester = new Pow.Solution();
        double[] inputs = {
            2.00000, 10.0, 1024.0,
            2.1, 3.0, 9.26100,
        };
        for (int i = 0; i < inputs.length / 3; i++) {
            double x = inputs[3 * i], ans = inputs[3 * i + 2];
            int n = (int) inputs[3 * i + 1];
            System.out.println (Printer.separator ());
            double output = tester.myPow (x, n);
            System.out.printf ("%f and %d -> %s, expected: %f\n", 
                x, n, Printer.wrapColor (output + "", output == ans ? "green" : "red"), ans
            );
        }
    }
}

大量的downvote, 估计是只接受数学解法, 大概看看, 不浪费时间了, 能写个搜索就写一个搜索解法; 另外, 之前有做过一题用/2来实现一般的除法, 这里不知道有没有类似的操作;

HAC上面看到的一个算法, 好像比较好记, 实现一下看看:

后来想了一下好像不行, 这个算法是只能解决integer的指数运算, 没有说double怎么做?

想不通, 不想了;

原来上面这个算法是可以的, 速度是24ms (10%). 注意处理一下负指数就行了;

不过写完了还是有一个小问题, 下面那个从右到左的方法, 实际上还是挺好理解的, 可以看一下editorial的文章, 讲的实际上很清楚, 就是一个利用了2的操作, 然后循环本身的一个优化; 但是这里这个从左到右的例子, 到底是什么原理? 怎么declarative的解释? 想了半天, 唯一的说法就是, 反正最后被square的次数是固定的, 从左到右从右到左都是无所谓的, 只要在有1的bit的位置, 记得多乘一个g就行了;

感觉这个解释实际上不是特别合理;


editorial

Approach #1 Brute Force [Time Limit Exceeded]

class Solution {  
    public double myPow(double x, int n) {  
        long N = n;  
        if (N < 0) {  
            x = 1 / x;  
            N = -N;  
        }  
        double ans = 1;  
        for (long i = 0; i < N; i++)  
            ans = ans * x;  
        return ans;  
    }  
};

Approach #2 Fast Power Algorithm Recursive [Accepted]

class Solution {  
    private double fastPow(double x, long n) {  
        if (n == 0) {  
            return 1.0;  
        }  
        double half = fastPow(x, n / 2);  
        if (n % 2 == 0) {  
            return half * half;  
        } else {  
            return half * half * x;  
        }  
    }  
    public double myPow(double x, int n) {  
        long N = n;  
        if (N < 0) {  
            x = 1 / x;  
            N = -N;  
        }  

        return fastPow(x, N);  
    }  
};

难怪讨骂好吧. 这个就是HAC上面的算法;

事实上, 这个就是我上面HAC上面看来的这个算法, 一模一样的; 我当时以为不能handle double, 不过这里看来, 实际上是可以的;

Approach #3 Fast Power Algorithm Iterative [Accepted]

class Solution {  
    public double myPow(double x, int n) {  
        long N = n;  
        if (N < 0) {  
            x = 1 / x;  
            N = -N;  
        }  
        double ans = 1;  
        double current_product = x;  
        for (long i = N; i > 0; i /= 2) {  
            if ((i % 2) == 1) {  
                ans = ans * current_product;  
            }  
            current_product = current_product * current_product;  
        }  
        return ans;  
    }  
};

不对, 实际上他这里实现的是这个:

不过其实这两个好像都是差不多的算法; 另外, 不要被这里的这个伪代码给骗到了, 实际上这个很好记忆, 循环里面的实际上直接就是A = S, S = S两个而已;

另外第三行的那个if e != 0其实可以看出来, 不是必须的, 反正下一个iteration也自动就terminate了;

这个算法也算是记下来了, 那我就实现我上面看到的从左到右的写法;


@pei-heng said in Short and easy to understand solution:

public class Solution {  
    public double pow(double x, int n) {  
        if(n == 0)  
            return 1;  
        if(n<0){  
            n = -n;  
            x = 1/x;  
        }  
        return (n%2 == 0) ? pow(x*x, n/2) : x*pow(x*x, n/2);  
    }  
}

@ChrisHuang said in Short and easy to understand solution:

If n is Integer.MIN_VALUE, the code will have overflow runtime error.

@4acreg said in Short and easy to understand solution:

you need one additional if statement

if( n < 0 ) {  
    if( n == Integer.MIN_VALUE ) {  
        ++n;  
        n = -n;  
        x = 1/x;  
        return x * x * pow( x * x, n / 2 );  
    }  
    n = -n;  
    x = 1 / x;  
}

@mingjun said in 5 different choices when talk with interviewers:

After reading some good sharing solutions, I'd like to show them together. You can see different ideas in the code.

1. nest myPow

double myPow(double x, int n) {  
    if(n<0) return 1/x * myPow(1/x, -(n+1));  
    if(n==0) return 1;  
    if(n==2) return x*x;  
    if(n%2==0) return myPow( myPow(x, n/2), 2);  
    else return x*myPow( myPow(x, n/2), 2);  
}  

2. double myPow

double myPow(double x, int n) {   
    if(n==0) return 1;  
    double t = myPow(x,n/2);  
    if(n%2) return n<0 ? 1/x*t*t : x*t*t;  
    else return t*t;  
}  

3. double x

double myPow(double x, int n) {   
    if(n==0) return 1;  
    if(n<0){  
        n = -n;  
        x = 1/x;  
    }  
    return n%2==0 ? myPow(x*x, n/2) : x*myPow(x*x, n/2);  
}  

4. iterative one

double myPow(double x, int n) {   
    if(n==0) return 1;  
    if(n<0) {  
        n = -n;  
        x = 1/x;  
    }  
    double ans = 1;  
    while(n>0){  
        if(n&1) ans *= x;  
        x *= x;  
        n >>= 1;  
    }  
    return ans;  
}  

5. bit operation

see this [solution][1]

If you have other ideas, please leave it below. Thanks.

[1]: https://leetcode.com/discuss/12004/my-answer-using-bit-operation-c-implementation

懒得看了;

另外一个处理因为flip导致的overflow的方法:

@aesi123 said in 5 different choices when talk with interviewers:

@shu.zhang As pointed earlier, it suffers from overflow.

You can convert n to -2147483646 before flipping the sign. (Convert it to -2147483647 will give you incorrect result if the base number is negative.)

不过到我现在提交为止, 好像这个bug其实都没有修复; 这里, 也看出来为什么在editorial里面, 都是先把n给cast到long了; 天天在这种corner case上面纠结, 确实是有点搞自己;

下面有一个也很好玩的解法:

@dingty said in 5 different choices when talk with interviewers:

Another iterative one like 4, may not be the fastest. The idea is to multiply x by n times, but with some speed up giving you an average O(log n) runtime.

class Solution {  
   public:  
    double myPow(double x, int n) {  
        if (!n) return 1.0;  
        if (n < 0) {  
            n = -(++n);  
            x = 1 / x;  
        } else  
            n--;  
        double result = x;  
        while (n) {  
            double y = x;  
            for (int i = 1; i > 0 && i <= n; i *= 2) {  
                result *= y;  
                y *= y;  
                n -= i;  
            }  
        }  
        return result;  
    }  
};

刚开始没有看懂, 那就画trace:

这里这个写法就能看出来这个问题跟除法那一题的相似性了, 两道题目都依赖于一个关键的信息, every integer is the sum of powers of 2. 当然, division那一题当时实际上是更难一点的, 但是这里上面这个人的解法, 其实就是利用了类似的观察;

但是感觉他这个最后实际上的算法跟division那题还是有点区别的, 因为如果按照sum of powers of 2的思路, 9不是应该是8 + 1这样分解就行了吗, 但是他这里的分解你可以看到, 实际上是1 + 1 + 2 + 4 + 1; 不理解背后是什么思路;

不过其实有所谓吗? 这题的核心点, 就是利用square和2之间的对应性; 反正最后只要拆分成power of 2, 哪怕你跟他这里这样, 拆的太细了, 也无所谓, 都可以使用类似的square来加速;

另外, 他这个拆分的具体的操作不知道是不是什么已知的套路;


@mathsam said in My answer using bit operation (C++ implementation):

class Solution {  
public:  
    double pow(double x, int n) {  
      if(n<0){  
          x = 1.0/x;  
          n = -n;  
      }  
      int unsigned m = n;  
        double tbl[32] = {0};  
        double result = 1;  
        tbl[0] = x;  
        for(int i=1;i<32;i++){  
            tbl[i] = tbl[i-1]*tbl[i-1];  
        }  
        for(int i=0;i<32;i++){  
            if( m & (0x1<<i) )  
            result *= tbl[i];  
        }  
        return result;  
    }  
};

In bit format and for a unsigned number, the number is represented as k0*2^0 + k1*2^1 + ... +k31*2^31. Therefore, once we know the pow(x,2^0), pow(x,2^1), ..., pow(x,2^31), we can get pow(x,n). And pow(x,2^m) can be constructed easily as pow(x,2^m) = pow(x,2^(m-1)*pow(x,2^(m-1).

这个就是把之前从右到左的算法给更加直白的描述了一点, 所有的base全都存下来, 虽然是没有必要的;


submission最优解: 19(75):

class Solution {  
    public double myPow(double x, int n) {  
        boolean isNegPow = false;  

        if (n < 0) {  
            x = 1 / x;  
            isNegPow = true;  
            n = -(n + 1); // Avoid overflow when pow == MIN_VALUE  
        }  

        double ans = 1, tmp = x;  

        while (n != 0) {  
            if (n % 2 == 1) {  
                ans *= tmp;  
            }   
            tmp *= tmp;  
            n /= 2;  
        }  

        if (isNegPow) {  
            ans *= x;  
        }  
        return ans;  
    }  
}

就是从右到左的写法, 看来比从左到右快一点; HAC书上说的那个从左到右更快, 看来也是未必;


Problem Description

Implement pow(x, n).

Example 1:

Input: 2.00000, 10  
Output: 1024.00000

Example 2:

Input: 2.10000, 3  
Output: 9.26100

Difficulty:Medium
Total Accepted:195.9K
Total Submissions:752.1K
Contributor:LeetCode
Companies
googlefacebookbloomberglinkedin
Related Topics
mathbinary search
Similar Questions
Sqrt(x)

results matching ""

    No results matching ""