【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)

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