-
Notifications
You must be signed in to change notification settings - Fork 0
283. Move Zeroes #51
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?
283. Move Zeroes #51
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,50 @@ | ||
| # 283. Move Zeroes | ||
|
|
||
| ゼロの最初のインデックスとノンゼロの最初のインデックスを覚えておいて、それらを入れ替える操作を続ければ良い | ||
|
|
||
| sol1.py: この操作を素直に書いた。が、コードが長くなって可読性が低い | ||
| sol2.py: 似た操作を関数化してわかりやすくしたつもり。ただし、同じアルゴリズムなのに関数の呼び出しによって速度が落ちてしまった | ||
|
|
||
| sol3.py: よく考えるとscannnig indexはnonzeroに対してのみ操作を行うので、forとif文で置き換えられることに気づく | ||
|
|
||
|
|
||
| ### コメントと他の方のコード | ||
|
|
||
| https://github.com/fhiyo/leetcode/pull/54/changes/BASE..40f6172e4c7a6b29303a6b66464dd512300ac477#diff-2f8b85074aa38861aa9dd6fbe0c5f1b540a06f8618d7552b4ffd05da21f795d3 | ||
|
|
||
| inplaceだけど他の配列を用意しても解くことはできる。 | ||
| inplaceの意味がなくなりそうだけど | ||
|
|
||
| 解法2は変数名までほぼ同じ。自然な解法ということだろうか。クイックソートのpartitionと似ているのはなるほど。 | ||
|
|
||
| https://github.com/fhiyo/leetcode/pull/54#discussion_r1729721970 | ||
|
|
||
| 関数化しているのも自分のと同じ考え方だ | ||
|
|
||
| https://github.com/olsen-blue/Arai60/pull/55#discussion_r2024137192 | ||
|
|
||
| > Generator を使って変なコードを書いてみました | ||
| > StopIteration を捕まえるのが正しいでしょうね。 | ||
| > next の第2引数の default を使えば例外がなくせますね。 | ||
|
|
||
| Generatorを使って走査するのか。自分では思いつきそうにない。 | ||
|
|
||
| https://github.com/shining-ai/leetcode/pull/54 | ||
|
|
||
| > first_zero_index というか、私の感覚は、ゼロが削除された文字列の長さですね。 | ||
|
|
||
| > https://en.wikipedia.org/wiki/Erase–remove_idiom | ||
| > Erase–remove idiom | ||
| > が頭に思い浮かんでいたら、助けになるかもしれません。 | ||
|
|
||
| 背景はこれなのかな。 | ||
| remove削除するように見せかけて削除条件に合わないものを前側によせるアルゴリズム。 | ||
| 削除だけを行うeraseでは毎回削除した要素の後ろにある要素を全て前に詰める必要がある。 | ||
| removeを行ったあとにeraseを行うと、要素を前に詰める操作を一回にまとめることができる | ||
|
|
||
|
|
||
| https://github.com/mamo3gr/arai60/blob/283_move-zeroes/283_move-zeroes/memo.md | ||
|
|
||
| https://github.com/mamo3gr/arai60/blob/283_move-zeroes/283_move-zeroes/step2_linked_list.py | ||
|
|
||
| Linked listを使って解いている |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| class Solution: | ||
| def moveZeroes(self, nums: List[int]) -> None: | ||
| """ | ||
| Do not return anything, modify nums in-place instead. | ||
| """ | ||
| scannning_index = 0 | ||
| while scannning_index < len(nums): | ||
| while scannning_index < len(nums) and nums[scannning_index] != 0: | ||
| scannning_index += 1 | ||
| if scannning_index == len(nums): | ||
| return | ||
| first_zero_index = scannning_index | ||
| while scannning_index < len(nums) and nums[scannning_index] == 0: | ||
| scannning_index += 1 | ||
| if scannning_index == len(nums): | ||
| return | ||
| while nums[first_zero_index] == 0 and scannning_index < len(nums): | ||
| nums[scannning_index], nums[first_zero_index] = ( | ||
| nums[first_zero_index], | ||
| nums[scannning_index], | ||
| ) | ||
| while scannning_index < len(nums) and nums[scannning_index] == 0: | ||
| scannning_index += 1 | ||
| first_zero_index += 1 | ||
|
|
||
| return |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| from unittest import skip | ||
|
|
||
|
|
||
| class Solution: | ||
| def moveZeroes(self, nums: List[int]) -> None: | ||
| """ | ||
| Do not return anything, modify nums in-place instead. | ||
| """ | ||
|
|
||
| def skip_index(index, zero_skip=True): | ||
| if zero_skip: | ||
| while index < len(nums) and nums[index] == 0: | ||
| index += 1 | ||
| else: | ||
| while index < len(nums) and nums[index] != 0: | ||
| index += 1 | ||
| return index | ||
|
|
||
| scanning_index = 0 | ||
| while scanning_index < len(nums): | ||
| first_zero_index = skip_index(scanning_index, zero_skip=False) | ||
| scanning_index = skip_index(first_zero_index, zero_skip=True) | ||
| if scanning_index == len(nums): | ||
| return | ||
| while nums[first_zero_index] == 0 and scanning_index < len(nums): | ||
| nums[scanning_index], nums[first_zero_index] = ( | ||
| nums[first_zero_index], | ||
| nums[scanning_index], | ||
| ) | ||
| scanning_index = skip_index(scanning_index, zero_skip=True) | ||
| first_zero_index += 1 | ||
|
|
||
| return | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| from unittest import skip | ||
|
|
||
|
|
||
| class Solution: | ||
| def moveZeroes(self, nums: List[int]) -> None: | ||
| """ | ||
| Do not return anything, modify nums in-place instead. | ||
| """ | ||
| last_non_zero_index = 0 | ||
|
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. ものすごく細かい話ですが、これを-1にして、ループ内で+=1してから処理をするか、それとも0にして処理後に+=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. 二分探索で閉区間か開区間かを考えるのに似ている、ということですかね。たしかに last か next か解釈は分かれそうです。今回は半開区間に対応していそうで、私の意図はこれだったのでそのままにしておきます。
というコメントもありましたので変数名に count を用いるのも一理あるな、と思いました |
||
| for index in range(len(nums)): | ||
| if nums[index] != 0: | ||
| nums[index], nums[last_non_zero_index] = ( | ||
| nums[last_non_zero_index], | ||
| nums[index], | ||
| ) | ||
| last_non_zero_index += 1 | ||
|
|
||
| return | ||
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.
自分なら skip_zeros と skip_non_zeros に分けるのですが、趣味の範囲だと思います。
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.
その点は迷ったのですが、処理がほぼ同じなので今回はまとめました。
関数を分ける選択をされる方がいることは参考になります。