-
Notifications
You must be signed in to change notification settings - Fork 0
50 pow x n medium #16
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?
Conversation
| if n < 0: | ||
| return self.myPow(1 / x, -n) | ||
| power_of_x = x | ||
| i = 0 |
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.
i を使わなくても書けるでしょうか?two_to_i が同様の情報を持っていそうです。
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.
確かに
if n >> i & 1:
...
の部分を
if n & two_to_i:
...
としても動くので、iを排除できますね。ただ可読性が下がるような印象です。
| i += 1 | ||
| two_to_i *= 2 | ||
| power_of_x = power_of_x * power_of_x | ||
| return x_to_n |
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.
個人的に x_to_n が x^n を意味するように読めませんでした。英語的には x to the n だと思いますが、省略しても伝わるかわかりませんでした。
他の方のPRを読んでみてどのような変数名が使われているか見てみるのも良いと思います。
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.
レビューありがとうございます。
power, poweredあたりが多いような印象でした。2のべき乗とxのべき乗をどちらも使うコードなので、これらの変数は余り適切でないように感じました。一方でより適切な変数は思いつきませんでした...
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.
2のべき乗は、n を二進数で表した時にある桁が 1 であるかを見ているので bit とすることもありだと思いました。
リンク先コードが正解というわけではありませんが、参考として共有いたします。
TORUS0818/leetcode#47 (comment)
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.
確かにビットシフトして計算しているのが伝わりやすい気がしました。ありがとうございます。
| half_n = n // 2 | ||
| remainder = n % 2 | ||
|
|
||
| return self.myPow(x, half_n) ** 2 * self.myPow(x, remainder) |
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.
remainder で場合分けした方が素直かなと個人的には思います。
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.
レビューありがとうございます。READMEで
(個人的には)n%2が1か0かで場合分けするよりも、remainderをそのままmyPowに渡す方がわかりやすいと感じた。数学的に必ずn=2*q+rならx^n=(x^q)^2 * (x)^rとなるため
と書いているように私はremainderを渡す方が直感的だと感じたのですが、場合分けの方が素直という意見もあるということですね。参考になります 🙏
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.
数式上はそうですが、結局 r は 0, 1 のみで、1 の場合は追加で x を掛ける、0 の場合は追加で掛けない、というのが繰り返し二乗法のポイントで、この関数の仕事として場合分けした方が見やすいと思っています。
| return self.myPow(x, n) | ||
|
|
||
| half_n = n // 2 | ||
| remainder = n % 2 |
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.
divmod を使うこともできますね。
https://docs.python.org/3.13/library/functions.html#divmod
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.
コメントありがとうございます。
「こんなのもあるよ」と教えてくださったのだとは思いますが、一応補足しますと、自分の以前のPR( #10 (comment) )のレビューにて、divmodが読みにくい、見慣れないというコメントがあったので、自分は//と%とで書くように心がけています。
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.
はい、どちらでも良いと思います!
問題へのリンク
50. Pow(x, n)
言語
Python
問題の概要
浮動小数点数
xと整数nが与えられたとき、xのn乗を計算する。自分の解法
step1
まず、繰り返し二乗法を再帰関数を用いて実装した。
nが偶数の場合はx^n = (x^(n/2))^2、奇数の場合はx^n = x * (x^((n-1)/2))^2となる性質を利用した再帰的な解法である。nを2で割っていくため、再帰の深さはlog(n)となる。O(log(n))。各nに対する計算は一度しか行われないためである。remainderは常に0または1であり、この計算はたかだか定数時間であるため、全体の計算量に大きな影響はない。(メモ化は不要)n%2が1か0かで場合分けするよりも、remainderをそのままmyPowに渡す方がわかりやすいと感じた。数学的に必ずn=2*q+rならx^n=(x^q)^2 * (x)^rとなるためO(log(n))。再帰呼び出しのスタックにlog(n)の空間が必要である。発見
**の挙動について、func(x) ** 2のような式はfunc(x)を1回だけ評価することを確認した。step2
step1の再帰実装では空間計算量が
O(log(n))であったため、これをO(1)に改善すべく、反復処理による実装に変更した。nを2進数として捉えるものである。例えばn=10(2進数で1010) の場合、x^10 = x^8 * x^2となる。nを右にシフト(n //= 2)しながら、最下位ビットが1かどうか(n % 2 == 1)を確認する。xのべき乗(x,x^2,x^4,x^8, ...)を結果に乗算していく。xのべき乗は、ループごとに自身を2乗することで効率的に計算される。O(log(n))。ループ回数がnのビット数に比例するためである。O(1)。変数の使用量がnの大きさに依存しないためである。step3
反復処理による実装
再帰関数による実装
step4 (FB)
別解・模範解答
次に解く問題の予告