-
Notifications
You must be signed in to change notification settings - Fork 0
Solved Arai60/50. Pow(x, n) #45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| ## Step 1. Initial Solution | ||
|
|
||
| - 素直にやるならx * x^(n-1)とする方法がある | ||
| - このまま取りあえず実装してみると再帰の深さがnになるので | ||
| • `-2^31 <= n <= 2^31-1` | ||
|
|
||
| を見ると微妙 | ||
|
|
||
| - 自分で計算するときは{x^(n//2)}^2のようにすることが多いのでこれを実装 | ||
| - 少し条件分岐が多くなったがひとまずこれで実装 | ||
|
|
||
| ```python | ||
| class Solution: | ||
| @cache | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. キャッシュがほとんど効かないと思いますので、外してよいと思います。 |
||
| def myPow(self, x: float, n: int) -> float: | ||
| if x == 0: | ||
| return 0 | ||
|
|
||
| if n < 0: | ||
| return 1 / self.myPow(x, -n) | ||
| if n == 0: | ||
| return 1 | ||
| if n == 1: | ||
| return x | ||
| if n == 2: | ||
| return x * x | ||
|
|
||
| if n % 2 == 1: | ||
| return x * self.myPow(x, n - 1) | ||
| return self.myPow(self.myPow(x, n // 2), 2) | ||
| ``` | ||
|
|
||
| ### Complexity Analysis | ||
|
|
||
| - 時間計算量:O(log n) | ||
| - 空間計算量:O(log n) | ||
|
|
||
| ## Step 2. Alternatives | ||
|
|
||
| - https://github.com/tokuhirat/LeetCode/pull/45/files#diff-ce284075b2a3f6e20cd3d4ff805c3cb4ab0540e9ace2b462e43b40955dfd3dc1R32 | ||
| - 中で x*xにする考え方もある | ||
| - 最後のelseは要らなさそう | ||
| - 分岐を参考にして修正 | ||
|
|
||
| ```python | ||
| class Solution: | ||
| @cache | ||
| def myPow(self, x: float, n: int) -> float: | ||
| if n < 0: | ||
| return 1 / self.myPow(x, -n) | ||
| if n == 0: | ||
| return 1 | ||
| if n % 2 == 1: | ||
| return x * self.myPow(x, n-1) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 二項演算子の左右には、適宜スペースを入れることをお勧めします。 参考までに、関連するスタイルガイドを共有いたします。 https://peps.python.org/pep-0008/#other-recommendations
https://google.github.io/styleguide/pyguide.html#36-whitespace
なお、これらのスタイルガイドは唯一絶対のルールではなく、数あるガイドラインの一つに過ぎません。チームによって重視する書き方が異なる場合もあります。 |
||
| return self.myPow(x, n // 2) * self.myPow(x, n // 2) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 一度変数に格納してから掛けたほうがシンプルだと思います。 p = self.myPow(x, n // 2)
return p * p |
||
| ``` | ||
|
|
||
| - https://github.com/TORUS0818/leetcode/pull/47/files#diff-91647df59bb2863e62120bcb064c143cab9cb1c4e78ed9feab30fc009844b5d0R198-R200 | ||
| - 確かにPythonではあまり気にすることがないが1.0表記の方がfloatであることが明らかなので良さそう | ||
| - x=0 かつ n≤0の場合は処理できないのでZeroDivisionErrorか0^0=1が返ることになる | ||
| - Step1の実装も正しくはないので微妙 | ||
| - https://github.com/TORUS0818/leetcode/pull/47/files#r2038337006 | ||
| - ビットシフトでループを回す方法もあるらしい | ||
| - 実際に手作業でこの演算をやることを考えるとあまり直感的ではない | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def myPow(self, x: float, n: int) -> float: | ||
| assert x != 0 or n > 0 | ||
| if n < 0: | ||
| x = 1.0 / x | ||
| n = -n | ||
|
|
||
| result = 1.0 | ||
| bit = 1 | ||
| exponent = x | ||
| while n >= bit: | ||
| if n & bit: | ||
| result *= exponent | ||
| bit <<= 1 | ||
| exponent *= exponent | ||
| return result | ||
| ``` | ||
|
|
||
| ## Step 3. Final Solution | ||
|
|
||
| - 以下でassert x ≠ 0 or n < 0を最初に入れてx==0の場合分けを入れないと答えが倍数精度で0.0表示になるときにエラーが起きる | ||
| - 再帰をするときは再帰で呼び出されるケースを網羅的に考える必要がある | ||
|
|
||
| ```python | ||
| class Solution: | ||
| @cache | ||
| def myPow(self, x: float, n: int) -> float: | ||
| assert x != 0 or n > 0 | ||
|
|
||
| if n == 0: | ||
| return 1.0 | ||
| if x == 0: | ||
| return 0 | ||
| if n < 0: | ||
| x = 1.0 / x | ||
| n = -n | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 好みですがn *= -1としてもいいと思いました。 |
||
|
|
||
| if n % 2 == 1: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. n % 2, n // 2についてはそれぞれn & 1, n >> 1とも書けるかもしれません。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. その視点はなかったですが今回のように計算用の関数の場合はそう言った観点も重要そうですね |
||
| return x * self.myPow(x, n-1) | ||
| return self.myPow(x*x, n//2) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. -, //の両隣はスペースを開ける方が自然な気がしました(もしかすると関数の引数としての区切りが明確になるという点でこういう場合は開けない方が好みという方もいるのでしょうか?)
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 自分はまとまっていた方が理解しやすいと思ってしまうタイプですが、一般的なのは開ける方な気はしています。。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. https://peps.python.org/pep-0008/#whitespace-in-expressions-and-statements スタイルは統一されていることが大事なので、あんまり局所的に正誤が決まるものであるというよりは周りを見て合わせるくらいがちょうどいいかと思います。 |
||
| ``` | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
再帰でやるのは思い付きませんでした。勉強になります 👀