Skip to content

283. Move Zeroes #54

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

283. Move Zeroes #54

wants to merge 1 commit into from

Conversation

fhiyo
Copy link
Owner

@fhiyo fhiyo commented Aug 17, 2024

for i in range(len(nums)):
if nums[i] == 0:
continue
nums[last_nonzero_index], nums[i] = nums[i], nums[last_nonzero_index]

Choose a reason for hiding this comment

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

もし時間にめちゃくちゃシビアな場合は、Step2の①の別解のスワップしない実装の方が速そうですね。(そんなシビアな事をpythonでするなという感じもありますが)
ただ、この方法の方が意味がわかりやすいのと、仮に仕様変更で0ではなくて0以下を端に寄せたいとなった場合にもcontinueする条件をnums[i] <= 0とするだけでワークするので、良いと思います。

この辺、3rdで最終的にこの方法を選んだ理由や考えが明示されていると良いかもしれないですね。

Copy link
Owner Author

Choose a reason for hiding this comment

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

3rdで最終的にこの方法を選んだ理由や考えが明示されていると良いかもしれないですね。

なるほど、これから書いてみます。ありがとうございます
ちなみに大体の場合は挙げた解法の中で自分なりに一番素直かなと思う方法で3rdを書いており、今回もそうです。動作が想像しやすいからか保守性も高くなることが多いかなと思い。

仮に仕様変更で0ではなくて0以下を端に寄せたいとなった場合にもcontinueする条件をnums[i] <= 0とするだけでワークする

こうは考えていかなったですが、たしかにそうですね

Copy link

Choose a reason for hiding this comment

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

まとめて 0 fill は、loop unrolling できたりするのでちょっと嬉しいこともあるでしょう。

- 空間計算量: O(1)

```py
class Solution:
Copy link

Choose a reason for hiding this comment

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

C++ の std:remove() を思い出しました。

last_nonzero_index = 0 # any elements in nums[:last_nonzero_index] are not 0
for i in range(len(nums)):
if nums[i] != 0:
nums[last_nonzero_index], nums[i] = nums[i], nums[last_nonzero_index]
Copy link

Choose a reason for hiding this comment

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

last_nonzero_indexだとそこより右にnonzeroが無いように一瞬思ってしまいましたが、それを防ぐための代案が難しいですね、、、

Copy link
Owner Author

Choose a reason for hiding this comment

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

一応上のコメントでnums[:last_nonzero_index]の各要素が非ゼロだよと補足してみましたが、名前自体変えた方が良さそうですかね?

Copy link

Choose a reason for hiding this comment

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

コメントだとlast_nonzero_indexより左に言及していますが、パッと読んだ時には右にはnonzeroの要素がないように思ってしましました。
nonzero_lengthとかの方がわかりやすいかな、難しい選択ですね

Copy link
Owner Author

Choose a reason for hiding this comment

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

なるほど、コメントだけにして単純にleftとかにして、ループ変数をrightとする方が変に迷わせないのかもと思いました

Comment on lines +114 to +115
while next_nonzero_index < len(nums) and nums[next_nonzero_index] == 0:
next_nonzero_index += 1
Copy link

Choose a reason for hiding this comment

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

L111~112と!= と==のみが違う操作なので、関数化してもいいかもですね

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

Choose a reason for hiding this comment

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

def find_leftmost_index_by_condition(nums, condition, index=0):
    while index < len(nums):
        if condition(nums[index]):
            return index
        index += 1
    return index

find_leftmost_index_by_condition(nums, last_nonzero_index, lambda x: x != 0)

みたいな感じですかね(思ったよりややこしかった)

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 moveZeroes(self, nums: List[int]) -> None:
        def find_leftmost_index_by(condition: Callable[[int], bool], start: int):
            i = start
            while i < len(nums) and not condition(nums[i]):
                i += 1
            return i

        next_nonzero_index = -1
        last_nonzero_index = 0 # any elements in nums[:last_nonzero_index] are not 0
        while True:
            last_nonzero_index = find_leftmost_index_by(lambda x: x == 0, last_nonzero_index)
            next_nonzero_index = find_leftmost_index_by(lambda x: x != 0, max(next_nonzero_index, last_nonzero_index))
            if next_nonzero_index == len(nums):
                break
            nums[last_nonzero_index], nums[next_nonzero_index] = nums[next_nonzero_index], nums[last_nonzero_index]
            last_nonzero_index += 1

自分なりに解釈してみました!PRのコードより良くなった気がします、ありがとうございます 🙏

Copy link

@nittoco nittoco Aug 24, 2024

Choose a reason for hiding this comment

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

おお、自分のやつより良くなってますね、ありがとうございます(後少し違っていた)

Copy link

Choose a reason for hiding this comment

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

Generator を使って変なコードを書いてみました。

class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        eq0 = (i for i, x in enumerate(nums) if x == 0)
        neq0 = (i for i, x in enumerate(nums) if x != 0)
        try:
            while 1:
                pos0 = next(eq0)
                while (posn0 := next(neq0)) < pos0:
                    pass
                nums[pos0], nums[posn0] = nums[posn0], nums[pos0]
        except:
            pass

Copy link

@nittoco nittoco Aug 24, 2024

Choose a reason for hiding this comment

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

try: 
    # なんかのエラーがある処理
except:
    pass

でエラーを消せるのなるほどでした

Copy link

Choose a reason for hiding this comment

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

このコードは遊びで書いているので、あまり参考にしないでください。

except ですべてを握りつぶすと、SIGINT つまり、キーボード入力の ^C も捕まえます。
https://discord.com/channels/1084280443945353267/1347375192065703986/1353569957581164615

StopIteration を捕まえるのが正しいでしょうね。

@rihib rihib mentioned this pull request Dec 17, 2024
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.

5 participants