【Leetcode】50. Pow(x, n)

题目地址:

https://leetcode.com/problems/powx-n/

快速幂(exponentiating by squaring)。基本思路是,要求xnx^n,我们可以先计算xn2x^{\lfloor\frac{n}{2}\rfloor},然后再回去求xnx^n,这类似于分治法,可以降低复杂度。有递归和非递归两种写法。

法1:含递归。由于测试数据里有一个n取Integer.MIN_VALUE这个样例,而这个值在计算机里是没有相反数的(也就是对于这个数,n=nn=-n,不存在其对应的正数),所以要用long来做。代码如下:

public class Solution {
    public double myPow(double x, int n) {
        return pow(x, n);
    }
    
    // 要用long来做
    private double pow(double x, long n) {
    	// base case是n = 0的情况
        if (n == 0) {
            return 1.0;
        }
    	// 如果n为负,就调整为正数来做。
        if (n < 0) {
            n = -n;
            x = 1.0 / x;
        }
    	// 分治
        double half = pow(x, n / 2);
        // 根据n的奇偶性来决定要不要额外乘一个x
        if (n % 2 == 0) {
            return half * half;
        } else {
            return half * half * x;
        }
    }
}

时空复杂度O(logn)O(\log n)

法2:非递归写法。主要思路是对nn做二进制展开,然后对这些二进制位从右向左扫描,用一个变量来保存到当前这个二进制位,xx的那么多次次方的结果是多少。

举个例子来说,如果要算x13x^{13},由于13=(1101)213=(1101)_2xx首先保存的是x20x^{2^0}是多少,也就是x1x^1,那其实就是xx。接着开始从右向左扫描11011101,扫描到第00位时遇到11,就给resres乘上x20x^{2^0},同时xx需要平方一下,这样就保存了x21x^{2^1}这个值,扫描到第11位时遇到00resres保持原样,而xx继续平方一下,得到了x22x^{2^2},继续扫描到11,这时resres乘一下x22x^{2^2},如此下去resres又乘了x23x^{2^3},扫描结束。我们统计一下会发现,res=x20x22x23=x20+22+23=x13res=x^{2^0}*x^{2^2}*x^{2^3}=x^{2^0+2^2+2^3}=x^{13},正好是所求结果。

代码如下:

public class Solution {
    public double myPow(double x, int n) {
        return pow(x, n);
    }
    
    private double pow(double x, long n) {
        if (n < 0) {
            n = -n;
            x = 1.0 / x;
        }
        
        double res = 1.0;
        while (n > 0) {
            if (n % 2 != 0) {
                res *= x;
            }
            x *= x;
            n >>= 1;
        }
        
        return res;
    }
}

时间复杂度O(logn)O(\log n),空间O(1)O(1)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章