Skip to content
Open
Show file tree
Hide file tree
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
66 changes: 66 additions & 0 deletions 82. Remove Duplicates from Sorted List II/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ほかの方が書かれたコードは読まれましたでしょうか?もしまだであれば、読まれることをお勧めいたします。また、読んだ際は、読んだソースコードのリンクと読んだときの所感を添えると、レビューワーにとって有益な情報となると思います。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

レビューして頂きありがとうございます!
他の方のコードも読んでみたのでメモ感覚で所感を書いてみます。
rimokem/arai60#4
こちらはwhile文を用いてポインタ操作で解いていて、再帰関数と比べてスタックオーバーフローの危険性がないのがGood point。気になったのはduplicatesがなくなったノードリストの一番最後のノードをtailとだけ変数で表していて、なんの後尾を表しているのかぱっと見わかりづらい。自分だったらno_duplicates_tailのように命名すると思う。
Zun-U/coding-practice-mochi0123#4
step1の方針では配列を別に作るというやり方を提案していたが、そうすると空間計算量がO(N)に増えてしまう。step3, 4を見るとPythonと比べると非常にコードが簡潔になっているが、dummyの役割のものにheadを紐付けることでprevNodeを軸にポインタ操作を行いより直感的なソースコードになっている。

## step1:
まず順番にノードを探索していって、head.valがhead.next.valと一致していればそれは重複したノードなのでそれらが消えるまでheadを進めていく。もしhead.valがhead.next.valでなければそれはdistinctなので答えで返すnodeとして追加するという方針で行く。しかし返すべき値をresとしてどのようにres自身に代入するか迷ったので、get_distinct_listという帰納関数を作りボトムアップでdistinctな連結リストを得て返すという方法を取った。

### code
```python
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:

def get_distinct_list(head_arg):
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

_arg は、外側の head と被らないようにするための接尾辞でしょうか。引数の名前を node にすると、外側の head と被らないと思いました。

if not head_arg or not head_arg.next:
return head_arg
if head_arg.val == head_arg.next.val:
while head_arg.next and head_arg.val == head_arg.next.val:
head_arg = head_arg.next
head_arg = head_arg.next
return get_distinct_list(head_arg)

head_arg.next = get_distinct_list(head_arg.next)
return head_arg

return get_distinct_list(head)
```

## step2:
get_distinct_listがやっていることとdeleteDuplicatesがやってることが同じだと気づいたのでdeleteDuplicates内でのget_distinct_listの宣言をやめてdeleteDuplicatesの帰納的呼び出しを行うことにした。

### code
```python
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

再帰関数無しでループで書く方法もあります。詳しくは、ほかの方が書かれたソースコードをご参照ください。


Copy link
Copy Markdown

Choose a reason for hiding this comment

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

関数宣言の次の行に空行を入れるのは、あまり見ないように思います。趣味の範囲かもしれません。

if not head or not head.next:
return head

if head.val == head.next.val:
while head.next and head.val == head.next.val:
head = head.next
head = head.next
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

head はリンクトリストの先頭のノードを表す単語です。そのため、 head が動いていくというのは、違和感を感じました。一旦 node 等の変数に格納し、それを動かしていくほうが自然だと思います。

return self.deleteDuplicates(head)

head.next = self.deleteDuplicates(head.next)
return head

```


## step3:
duplicateだった場合に最後head = head.nextとやってるがそのままhead.nextを代入すればいいと気づいたのでhead = head.nextを消した。

### code
```python
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head or not head.next:
return head

if head.val == head.next.val:
while head.next and head.val == head.next.val:
head = head.next
return self.deleteDuplicates(head.next)

head.next = self.deleteDuplicates(head.next)
return head

```
21 changes: 21 additions & 0 deletions 82. Remove Duplicates from Sorted List II/step1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:

def get_distinct_list(head_arg):
if not head_arg or not head_arg.next:
return head_arg
if head_arg.val == head_arg.next.val:
while head_arg.next and head_arg.val == head_arg.next.val:
head_arg = head_arg.next
head_arg = head_arg.next
return get_distinct_list(head_arg)

head_arg.next = get_distinct_list(head_arg.next)
return head_arg

return get_distinct_list(head)
19 changes: 19 additions & 0 deletions 82. Remove Duplicates from Sorted List II/step2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:

if not head or not head.next:
return head

if head.val == head.next.val:
while head.next and head.val == head.next.val:
head = head.next
head = head.next
return self.deleteDuplicates(head)

head.next = self.deleteDuplicates(head.next)
return head
17 changes: 17 additions & 0 deletions 82. Remove Duplicates from Sorted List II/step3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head or not head.next:
return head

if head.val == head.next.val:
while head.next and head.val == head.next.val:
head = head.next
return self.deleteDuplicates(head.next)

head.next = self.deleteDuplicates(head.next)
return head