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
171 changes: 171 additions & 0 deletions 83. Remove Duplicates from Sorted List.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
# step1
重複要素を削除するという文言だけ読むとsetを使いたくなるが、Listnodeはiterableじゃないので使えない。

```
TypeError: 'ListNode' object is not iterable
a = set(head)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

a = set()
a.add(head) なら使えそうですね
https://docs.python.org/ja/3/library/stdtypes.html#set.add

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.

ありがとうございます!

試してみた結果、listnodeは各nodeのオブジェクトが別なので削除されないという理解をしました

`

    # リストからsetへすることで重複の排除は可能
    a = [1,1,1]
    b = set(a)
    print(b)
    # stdout: {1}

    # set後のprint(a)は波かっこ{}にはいっているので、set型への変換はできているが、Listnodeの重複は削除できないみたい
    print(head)
    c = set()
    c.add(head)
    print(c)
    # ListNode{val: 1, next: ListNode{val: 1, next: ListNode{val: 2, next: None}}}
    # {ListNode{val: 1, next: ListNode{val: 1, next: ListNode{val: 2, next: None}}}}

   # 値が同じなので削除されるかと思った       
    print(id(a[0]))
    print(id(a[1]))
    print(id(head.val))
    print(id(head.next.val))
    # 10851480
    # 10851480
    # 10851480
    # 10851480
    
    # node自体のidは別なので削除されないということで理解した
    print(id(head))
    print(id(head.next))
    # 140619481748816
    # 140619481728976

`

```

head = [1,1,2]の場合
outputは[1,2]

なのとソートされているので、重複している場合、同じ数字が連続で入ってくる。

if head.val == head.nextのとき,head.nextを削除する感じ?

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

Choose a reason for hiding this comment

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

こちらのコメントをご参照ください。
riku359/LeetCode#9 (comment)

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.

ありがとうございます、適切な変数名が選べるように意識したいと思います

print(current.val)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

コードレビューを依頼する際は、デバッグ用の print は削除してからのほうが良いと思います。理由は、 print が読み手にとってノイズに感じられる場合があるためです。

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.

承知しました

while current is not None:
print(current.val)
if current.val == current.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.

値とノードを比較してしまっているようです。

print(current.nextを削除する)
current = current.next
return current
```

printが出ない。head.next.のvalか。

```python
# 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]:
current = head
print(current)
print(current.val)
while current is not None:
print(current.val)
if current.val == current.next.val:
print("current.nextを削除する")
current.next = current.next.next
current = current.next
return current
```

current.nextを削除するというよりも、listnodeは(1,next)->(1,next)->(2,next)
nextを2のところを指すようにするのかな

currentはheadを参照していて、currentを操作するとheadのlistnodeも変更が加わる。なのでreturn

```python
# 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]:
current = head
print(current)
print(current.val)
while current and current.next is not None:
print(current.val)
if current.val == current.next.val:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

whlie current.next is not None and current.val == current.next.val:

にして、値が一致し続ける限り次に繋ぎ変え続けるようにすると、意図通り動くと思います。ただし、次のノードが存在することをチェックしないと、末尾に到達したときにエラーになります。

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.

ありがとうございます!内側のwhileで一致し続ける限り回して、一致しなくなったらnode.nextして外側のwhileで回す。内側のwhileのnode.next is not Noneを書かないと、node.valでnoneの属性がないのでエラーになる。

class Solution:
    def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
        node = head
        while node is not None:
            while node.next is not None and node.val == node.next.val:
                node.next = node.next.next
            node = node.next
        return head

print("current.nextを削除する")
current.next = current.next.next
current = current.next
return head
```

[1,1,1]のときに通らない。出力を見ると、if文に1回しか入っていない。

[1(A),1(B),1(C)]としたときに、

if文の中はcurrent.next(B) = current.next(C)

出た後に

current = current.next(C)

で次のループでcurrentが(C)でcurrent.nextがNoneになってしまって終わっている。なので条件に合致しない場合のみcurrent = current.nextで進めるようにする

```python
# 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]:
current = head
while current is not None and current.next is not None:
print(current.val)
if current.val == current.next.val:
print("a")
current.next = current.next.next
else:
current = current.next
return head
```

# step2
PRを見ていく
いくつかコメントももらっているので、修正していく

- 変数名currentの情報量がすくないのでnodeにする
 - 情報量を増やすならcurrent_nodeも良さげだが長ければ良いわけではない
- https://discord.com/channels/1084280443945353267/1200089668901937312/1207200647594639391
- 命名の感覚はこのあたりもhttps://discord.com/channels/1084280443945353267/1200089668901937312/1209882689411223644
- 関数内の主役なら1,2単語、ループを出ても使うような変数名は分かりやすい名前を付けてあげる
- 日本語でやる場合はどうつけるか
- デバッグ用print文は消す
- valueとnodeの比較をしている箇所
- 中身を理解せずにやりたいことが先行してしまってそのまま書いちゃってるのかもしれない
- 再帰で呼び出す方法
- https://github.com/attractal/leetcode/pull/3/changes
- 再帰の深さの限界などの制約もあるので、使いどころは見極める必要がありそう

# step3

考えずに書くと最後のreturnをnodeにしそう。nodeはwhileの中で操作しているので最後のnodeの値が入っている({val:2,next: None}のような)。

node is not Noneはnodeが空のときのための条件。whileの前に書いてもいいかも。

```python
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
node = head
while node is not None and node.next is not None:
if node.val == node.next.val:
node.next = node.next.next
else:
node = node.next
return head
```

if node is Noneを先に書く方法を試したときにif文のnode.valにするのを忘れた。脳のリソースがそっちに割かれたのかもしれない。

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

if node is None:
return head
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ここはreturn None の方が好きです。頭を余計に使わないので

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.

確かに一瞬戻ったり考えたりしますね

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

少し気にするだけで、下の return None (第165行)よりも、こちらの return head の方が分かりやすいと思います。
ただ、自分は while node is not None and node.next is not None: が一番好きです。

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.

ありがとうございます!
選択肢としていろいろな書き方ができるようにしたいと思います

while node.next is not None:
if node.val == node.next.val:
node.next = node.next.next
else:
node = node.next
return head
```

```python
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
node = head
if node is None:
return None
while node.next is not None:
if node.val == node.next.val:
node.next = node.next.next
else:
node = node.next
return head
```