[Leetcode解題] 50. Pow(x, n)
26 October 2024
medium
recursion
題目描述
50. Pow(x, n) 這題要實作一個指數計算函數 pow(x, n),這個函數會計算並回傳 x 的 n 次方,也就是 $x^n$。n 可以是正數、零、或負數,並且 x 可能是小數(例如 2.5)。
解題思路
這題的重點是效率,如果只是簡單地重複相乘,當 n 很大時,計算會變得非常慢。因此我們可以使用 Divide and conquer來加速計算。
Divide and conquer的核心思路是利用指數的特性來把計算「拆解」:
- 當
n是偶數時,將問題拆成兩個一樣的子問題: $x^n = (x^{n/2}) \times (x^{n/2})$ - 當
n是奇數時,則要多乘上一個x: $x^n = x \times (x^{(n-1)/2}) \times (x^{(n-1)/2})$ - 當
n是負數時,只要計算 $x^{-n}$ 再取倒數就可以了,因為 $x^{-n} = \frac{1}{x^n}$。
這樣的做法讓我們可以把問題逐步地對半切割,讓時間複雜度從 O(n) 降低到 O(log n)。
Python 實作
以下是 Python 的解法,使用遞迴來實作:
class Solution:
def myPow(self, x: float, n: int) -> float:
if n == 0:
return 1
if n < 0:
x = 1 / x
n = -n
half = self.myPow(x, n // 2)
if n % 2 == 0:
return half * half
else:
return half * half * x
C++ 實作
C++ 的解法跟 Python 類似,也使用遞迴,程式碼如下:
INT_MIN 時可能發生的溢位問題 在 C++ 中,
int的範圍是 $[-2^{31}, 2^{31}-1]$,所以當n等於INT_MIN(即 $-2^{31}$)時,取相反數會超出int的範圍,因為 $(-(-2^{31})$ 並不在int的可表示範圍內,會造成溢位問題。 因此當我們要計算 $\frac{1}{x^n}$,我們先計算 $\frac{1}{x^{(-n+1)}}$ (就是1 / myPow(x, -(n+1))),然後再額外除以x來補上「少算」的一次乘積(即x的額外一次倒數)。class Solution { public: double myPow(double x, int n) { if (n==0) return 1; if (n<0) return 1/ myPow(x, -(n+1)) / x; double t = myPow(x, n/2); if (n%2) return t*t*x; else return t*t; } };
時間複雜度分析
這個解法的時間複雜度是 $O(log n)$。原因是我們每次都將指數 n 對半縮小,讓計算量隨著指數的減小而成指數級地減少。