冪次方的四種快速取法(不使用pow函數)


Pow(x, n)

  • 方法一:暴力法
  • 方法二:遞歸快速冪算法
  • 方法三:迭代快速冪算法
  • 方法四:位運算法

方法一:暴力法

思路

只需模擬將 x 相乘 n 次的過程。

如果 \(n < 0\),我們可以直接用 \(\dfrac{1}{x}\), \(-n\) 來替換 \(x , n\) 以保證 \(n \ge 0\)。該限制可以簡化我們的進一步討論。

但我們需要注意極端情況,尤其是負整數和正整數的不同范圍限制。

算法

我們可以用一個簡單的循環來計算結果。

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

復雜度分析

  • 時間復雜度:\(O(n)\)。我們將 x 相乘 n 次。
  • 空間復雜度:\(O(1)\)。我們需要一個變量來存儲 x 的最終結果。

方法二:遞歸快速冪算法

class Solution {
public:
    double fastPow(double x, long 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;
        }
    }
    double myPow(double x, int n) {
        long long N = n;
        if (N < 0) {
            x = 1 / x;
            N = -N;
        }
        return fastPow(x, N);
    }
};

復雜度分析

  • 時間復雜度:O(log(n))O(log(n))。每次我們應用公式$ (x ^ n) ^ 2 = x ^ {2 * n}\(,\)n$ 就減少一半。 因此,我們最多需要 \(O(log(n))\)次計算來得到結果。
  • 空間復雜度:\(O(log(n))\)。每次計算,我們都需要存儲 \(x ^ {n / 2}\) 的結果。 我們需要計算 \(O(log(n))\)次,因此空間復雜度為 \(O(log(n))\)

方法三:迭代快速冪算法

遞歸或迭代的快速冪實際上是實現同一目標的不同方式。

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

復雜度分析

  • 時間復雜度:\(O(log(n))\)。對於 n 的每個二進制位,我們最多只能乘一次。所以總的時間復雜度為 \(O(log(n))\)
  • 空間復雜度:\(O(1)\)。我們只需要兩個變量來存儲 x 的當前乘積和最終結果。

位運算實現pow(x,n)

根據暴力法的思路來看特別簡單,但通過位運算呢?

位運算技巧

我舉個例子吧,例如 n = 13,則 n 的二進制表示為 1101, 那么 m 的 13 次方可以拆解為:

\(m^{1101} = m^{0001} * m^{0100} * m^{1000}\)

我們可以通過 & 1和 >>1 來逐位讀取 1101,為1時將該位代表的乘數累乘到最終結果。直接看代碼吧,反而容易理解:

int pow(int n){
    int sum = 1;
    int tmp = m;
    while(n != 0){
        if(n & 1 == 1){
            sum *= tmp;
        }
        tmp *= tmp;
        n = n >> 1;
    }
    return sum;
}

時間復雜度近為 \(O(logn)\),而且看起來很牛逼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM