Skip to content
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

50. Pow(x, n) #41

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open

50. Pow(x, n) #41

wants to merge 5 commits into from

Conversation

hayashi-ay
Copy link
Owner

if n == 0:
return 1
if n < 0:
return 1 / self.myPow(x, -n)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

n を正の数に変換するために再帰呼び出しをしている点は理解できるのですが、読んでいてやや認知負荷が高いです。もう少し平易な書き方はできますでしょうか?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return self.myPow(1 / x, -n)

これだと負荷が減りますか?

if n < 0:
return 1 / self.myPow(x, -n)
if n % 2:
return x * self.myPow(x * x, n // 2)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

この再帰はループで表現したほうが、読んでいて認知負荷が低くなると思います。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Iterativeで書いてみました。個人的には再帰の方が直感的に思え読みやすいなと思いました。
ただ読みやすさに議論の余地があるなら関数呼び出しを行わず空間計算量がO(1)のループに分があるような気がします。

class Solution:
    def myPow(self, x: float, n: int) -> float:
        if n == 0:
            return 1
        if n < 0:
            x = 1 / x
            n = -n
        cumprod = 1
        while n > 0:
            if n % 2:
                cumprod *= x
            x *= x
            n //= 2
        return cumprod

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ループと再帰、どちらが認知負荷が低くなるか、直感的に思えるかは、個人差があると思います。業務でコードを書く場合は、平均的な開発メンバーにとって、どちらが認知負荷が低いか、直感的に思えるか感触を確かめ、そちらで書くのが良いと思います。また、もしコーディングインタビューでどちらで書くか迷った場合は、面接官に対しどちらで書こうか迷っている、どちらで書くのが良いか?と聞いてしまっても良いと思います。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

選択肢の幅があることが大事ですね。

個人的には再帰の方が直感的に思え読みやすいなと思いました。

もう少し言語化してみました。再帰の方がTop Downで宣言的に書けることが多いのに対して、ループだとBottom Upで書く必要があるので、再帰の方が読みやすいのかなと思いました。

if n == 0:
return 1
if n < 0:
return self.myPow(1 / x, -n)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

n の符号と絶対値を保存しておき、 n の符号が負の場合は最後に 1 / hoge としたほうが、読んでいて認知負荷が低くなると思います。

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

よくよく考えたところ、

if n < 0:
    n = -n
    x = 1.0 / x

でよいような気がしてきました。

if n < 0:
return self.myPow(1 / x, -n)
res = 1
digits = x
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

digits ですと、複数の桁を表すことになり、変数の本来の意味から離れるように思います。代案として、累積を表す cumulated あたりはいかがでしょうか?形容詞のためやや微妙かもしれませんが…。

Copy link
Owner Author

@hayashi-ay hayashi-ay Mar 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

累積積(cumulative product)が良いかなと思いました。ちょっと長いのでcumprodにしました。

命名などを見直して再度書き直しました。

class Solution:
    def myPow(self, x: float, n: int) -> float:
        if n == 0:
            return 1
        if n < 0:
            x = 1 / x
            n = -n
        # left to right binary exponentation
        # exponeitationを2進数表記して2進数表記の各桁ごとに分解する
        # 例) 3^14 = 3^(2^3) * 3^(2^2) * 3^(2^1)
        cumprod = 1
        powered = x
        while n > 0:
            if n % 2:
                cumprod *= powered
            powered *= powered
            n >>= 1
        return cumprod

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

指摘と命名逆かも。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

class Solution:
    def myPow(self, x: float, n: int) -> float:
        if n == 0:
            return 1
        if n < 0:
            x = 1 / x
            n = -n
        # left to right binary exponentation
        # exponeitationを2進数表記して2進数表記の各桁ごとに分解する
        # 例) 3^14 = 3^(2^3) * 3^(2^2) * 3^(2^1)
        powered = 1
        cumprod = x
        while n > 0:
            if n % 2:
                powered *= cumprod
            cumprod *= cumprod
            n >>= 1
        return powered

return 1
if n < 0:
return self.myPow(1 / x, -n)
res = 1
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

この変数に保持される値を表す、具体的な変数名を付けたほうが良いと思います。 powered あたりでしょうか…。形容詞のためやや微妙かもしれません…。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

思いつかなかったのでres(result)にしたのですがpoweredの方が良さそうです。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants