# LeetCode Medium 50. Pow(x, n)
tags: leetcode
問題
$x^{n}$を計算する
pow(x, n)
を実装せよ注意: $$ -100.0 < x < 100.0 $$ $$ n \in [- 2^{31}, 2^{31}) $$
解法1(recursive)
愚直に実装するとx
をn
回掛ける必要があるので時間計算量が$O(n)$となり効率が悪いです
改善するために下の工夫をします
- 基底は$n=0$のときです.このとき$1$を返します
- $n$が偶数の時は$x^{n}$を$x^{2 \cdot n/2}$と表せることを使って
pow(x*x, n/2)
を再帰的に実行します - また$n$が奇数のときは$n-1$として偶数にして上の処理をした関数の帰り値に
x
を掛けます - $n < 0$のときは
x = 1/x
,n = -n
として再帰関数を実行します - 空間計算量は上の処理で$n=2^{x}$である$x$回だけ実行すればよいので, $O(\log(n))$
- 時間計算量も$O(\log(n))$です
Python
再帰回数の上限
Pythonは再帰関数の上限が決まっています.以下のコードでその上限値を見ることが可能です
import sys print(sys.getrecursionlimit()) # 1000
この問題では再帰で実装した際に上限に達してしまう可能性があるのでこの上限を変更します
sys.setrecursionlimit(10 ** 9)
今回は上限を変えなくても大丈夫です(LeetCodeに関して言えば, これを使っているときはアルゴリズムがおかしい可能性が高い気がします)
コード
class Solution: def myPow(self, x: float, n: int) -> float: if n < 0: return self.myPow(1/x, -n) elif n == 0: return 1 elif n % 2 == 1: return x * self.myPow(x*x, n//2) else: return self.myPow(x*x, n//2)
C++
C++ではmyPow
のみを使って再帰での実装は出来ないはずです
lambda
やhelper
関数を使えばできるかも知れませんがおそらくこの点で聞きたいのは2の補数を理解しているかなのでいらないと思います
C++のint
型は$[- 2^{31}, 2^{{31}})$です
つまり負の数の最大値の絶対値は正の数の最大値の絶対値よりも1大きいです
そのためC++では次の方法で実装すると上手く行かないです
下は上手く行かない例です
class Solution { public: double myPow(double x, int n) { if (n < 0) { return myPow(1/x, -n); } else if (n == 0) { return 1; } else if (n & 1) { return x * myPow(x*x, n/2); } else { return myPow(x*x, n/2); } } };
解法2(iterative)
- 上と同じことをします
- 再帰関数を使わないで返り値となる変数を使います(ここでは
res
) - 空間計算量と時間計算量はrecursiveのときと変わりません
Python
class Solution: def myPow(self, x: float, n: int) -> float: if n == 0: return 1 else: res = 1 if n < 0: x, n = 1/x, -n while n != 0: if n & 1: res *= x x *= x n //= 2 return res
C++
class Solution { public: double myPow(double x, int n) { double res = 1.0; for (int i = n; i ; i /= 2) { if (i & 1) res *= x; x *= x; } if (n >= 0) { return res; } else { return 1 / res; } } };
ちなみに
Pythonならこう書けば終わりです...(身も蓋もない)
return x**n