Skip to content

82. Remove Duplicates from Sorted List II.md #4

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 4 commits into
base: main
Choose a base branch
from
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
167 changes: 167 additions & 0 deletions 82. Remove Duplicates from Sorted List II.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
82. Remove Duplicates from Sorted List II.md
基本的に思考順に書いていく
他の人の発言の引用には「」をつける

step1 not accepted
```python
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
result = node = head

while node is not None:
if node.val == node.next.val:
if node.next.val == node.next.next.val:
node = node.next
node.next = node.next.next
node = node.next.next
else:
node = node.next
return result
```
以下はエラー文。
```python
AttributeError: 'NoneType' object has no attribute 'val'
^^^^^^^^^^^^^
if node.val == node.next.val:
Line 13 in deleteDuplicates (Solution.py)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ret = Solution().deleteDuplicates(param_1)
Line 46 in _driver (Solution.py)
_driver()
Line 61 in <module> (Solution.py)
```
headを参照しているnodeが属性valを持たないのは何故?
ーー(73行目まで書いて気づいたが、これはnodeがNoneになっている、つまりもうnodeはないのにvalを求めてるせい。node is not Noneの条件を書けば良かった。)

araiさんの動画を見た(https://www.youtube.com/watch?v=Y2gxc-p-KsI)
最初にダミーのnodeを置くsentinel nodeというテクニックがあることを知った。
(https://ja.wikipedia.org/wiki/%E7%95%AA%E5%85%B5)
sentinel nodeはデータの終了を示す特殊なデータのこと。

重複を見つけたら重複部分の終わり、つまり最後の重複のnextを前のノードを繋ぐ。
先頭に重複が来ることを想定してsentinel nodeを用意する。

olsen-blueさんのgitを読んでみた
(https://github.com/olsen-blue/Arai60/pull/4)

araiさんや他の人のgitを見るとdummyで書いていたが、sentinelは有名な呼び方じゃないのかな。
sentinelで書こうと思ったがdummyという変数名で書くことにする。
Copy link

Choose a reason for hiding this comment

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

これはどちらでもいいでしょう。

もう少し書き方のオプションや何を引き継ぐ約束でループを回しているのかについて、考えるために下のドキュメントを貼っておきます。どこまで掘り下げるかはオプショナルです。
https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.xzxd7jwvkwc5


step2
```python
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode(0,head)
last_non_duplicate_node = dummy
node = head

while node is not None and node.next is not None:

Copy link

Choose a reason for hiding this comment

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

while 文の直後に空行を入れるのはあまり見ないかもしれません。好みの問題かもしれません。

if node.val == node.next.val and node.next is not None:
while node.next is not None and node.val == node.next.val:
node = node.next
last_non_duplicate_node.next = node.next

else:
last_non_duplicate_node = last_non_duplicate_node.next

node = node.next

return dummy.next
```
olsen-blueさんのコードを参考に書いた。
変数名だけ変更したが長すぎてあまり良くない

whileやifの条件文を逆に書いたときエラーを吐いたので調べると短絡評価が原因っぽい。
andやorは必ずしも全て評価するわけではなく、以下のように評価していく。
orは短絡評価されます。つまり第一引数が偽のときにのみ、第二引数が評価されます。
andは短絡評価されます。つまり第一引数が真のときにのみ、第二引数が評価されます。
(https://docs.python.org/ja/3.10/library/stdtypes.html?highlight=set)

以下はエラーが出た書き方。
```python
if node.val == node.next.val and node.next is not None:
while node.val == node.next.val and node.next is not None:
node = node.next
last_non_duplicate_node.next = node.next
```
whileのところで引っかかったが、それはnodeがどんどん進んでいきnode.nextがNoneになったとき、while内で node.val == node.next.valを評価しようとしたため。
node.nextはNoneだからvalは持っていない。そのためエラーが起きた。

last_non_duplicate_nodeはやっぱり長すぎるのでlast_fixed_nodeにする。

step2-1 not accepted
```python
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode(0,head)
last_fixed_node = dummy
node = head

while node is not None and node.next is not None:

if node.next is not None and node.val == node.next.val:
while node.next is not None and node.val == node.next.val:
node = node.next
last_fixed_node = node.next

else:
last_fixed_node = last_fixed_node.next
node = node.next
return dummy.next
```
106行目がlast_fixed_node.next = node.nextにできていなかった。

step3
1回目 2分39
2回目 失敗(last_fixed_node.next = node.nextのところをまた間違えた)

1回目 2分28
2回目 2分21
3回目 2分
```python
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode(0,head)
last_fixed_node = dummy
node = head

while node is not None and node.next is not None:

if node.next is not None and node.val == node.next.val:
while node.next is not None and node.val == node.next.val:
node = node.next
last_fixed_node.next = node.next

else:
last_fixed_node = last_fixed_node.next

node = node.next

Copy link

Choose a reason for hiding this comment

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

関数内で空行を入れる際は 1 行のみとするのが良いと思います。

https://google.github.io/styleguide/pyguide.html#35-blank-lines

Use single blank lines as you judge appropriate within functions or methods.



return dummy.next
```
時間計算量はdummyと一緒に末尾まで進んでいるためO(2N)
空間計算量はdummyも用意しているためO(2)

レビューを受けて書き直したコードが以下
```python
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode(0,head)
last_fixed_node = dummy
node = head

while node is not None and node.next is not None:
if node.next is not None and node.val == node.next.val:
while node.next is not None and node.val == node.next.val:
node = node.next
last_fixed_node.next = node.next

else:
last_fixed_node = last_fixed_node.next

node = node.next
return dummy.next
```