Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions Python3/283. Move Zeroes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
## Step 1. Initial Solution

- 前から見て行って0が出てきたら後ろに持っていく
- popしてappendするか代入するか
- 全部ずらす処理を書くよりはpopの方が分かりやすい
- for文で見ていくと後ろが0だけになったときに無限ループするので0の出現回数を保持

```python
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
zero_count = 0
for i in range(len(nums)):
while nums[i] == 0 and i < len(nums) - zero_count:
nums.pop(i)
nums.append(0)
zero_count += 1
```

### Complexity Analysis

- 時間計算量:O(N^2)
- 空間計算量:O(1)

## Step 2. Alternatives

- Follow upに最小のオペレーション数でやる方法は?とあるので考えてみる
- 0の出現箇所を保持して線形に処理(O(N))

```python
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
non_zero_indices = []
nums_len = len(nums)

for i in range(len(nums)):
if nums[i] != 0:
non_zero_indices.append(i)

nums_non_zero = len(non_zero_indices)
for i in range(nums_len):
Copy link

Choose a reason for hiding this comment

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

nums[i] = nums[non_zero_indices[i]]

を行うループと、

nums[i] = 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.

これは少し迷いましたがそれでも良いですね

if i < nums_non_zero:
nums[i] = nums[non_zero_indices[i]]
continue
nums[i] = 0
```

- 0の出現回数だけ保持してあとで0を足す方法

```python
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
index = 0
zero_count = 0
nums_len = len(nums)
while index + zero_count < nums_len:
Comment on lines +61 to +64

Choose a reason for hiding this comment

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

indexをnon_zero_countと命名するとループ継続条件がより明快になりそうです。

あるいは、indexは必ずindex + zero_countの形でしか使わないのでこれをindexやiとする方が自然に感じます。

Copy link
Owner Author

Choose a reason for hiding this comment

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

その書き方の人は確かにちらほら見かけましたね、ご意見ありがとうございます

if nums[index + zero_count] == 0:
zero_count += 1
continue
nums[index] = nums[index + zero_count]
index += 1
for i in range(index, nums_len):
nums[i] = 0
```

- https://github.com/tokuhirat/LeetCode/pull/54/files#diff-8e38546decaf9631b00de9e6cb4e27b61427defe98e3406a20c969beaa9f7d18R33
- この書き方はとてもシンプルで分かりやすい
- x, y = y, xという書き方が出来ることはあまり分かっていなかった
- 右側の評価をして (y, x)のタプル作成→代入、という流れで処理されるらしい
- https://github.com/shining-ai/leetcode/pull/54/files#diff-326ca2ce90ef5e7bf7e21c2676a184474a21c4d3d213d13c81e3fc5675c23267R4
- これも読みやすい
- 0の時の処理はスキップの方が分岐ごとの処理が見やすくなる
- https://github.com/shintaro1993/arai60/pull/58/files#diff-f10c3b5bb7c73707f74cd5cd8e947fd5882cdde6933460eeba70f9d1b19d840cR31-R40
- このあたりも忘れずに考えたい
- O(N^2)だと>10^8ステップなので1秒以上かかる

## Step 3. Final Solution

- 一番シンプルに感じたもので実装
Copy link

Choose a reason for hiding this comment

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

特に問題ないかと思います。
erase remove idiom を連想したので調べておいてください。


```python
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
non_zero_count = 0
for i in range(len(nums)):
if nums[i] == 0:
continue
nums[non_zero_count], nums[i] = nums[i], nums[non_zero_count]
non_zero_count += 1
```