Skip to content

83. Remove Duplicates from Sorted List.md #3

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 5 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
155 changes: 155 additions & 0 deletions 83. Remove Duplicates from Sorted List.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
83. Remove Duplicates from Sorted List.md

思考順に書いていく
誰かの発言の引用は「」でおこなう

step1 not accpetd
```python
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
node = head
visited = set()
node_number_sum = len(head)

for i in range(node_number_sum):
if node in set:
visited.remove(node)

visited.add(node)
node = node.next

visited.sort()
return visited
```
以下はエラー文
TypeError: object of type 'ListNode' has no len()
^^^^^^^^^
node_number_sum = len(head)
Line 10 in deleteDuplicates (Solution.py)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ret = Solution().deleteDuplicates(param_1)
Line 48 in _driver (Solution.py)
_driver()
Line 63 in <module> (Solution.py)


lenが期待している型とheadの型が違うみたい
でもheadはリストなのになぜ入らないの?

そもそもheadの理解が浅かったと感じたのでprint(head)で中身を見てみる
```python
ListNode{val: 1, next: ListNode{val: 1, next: ListNode{val: 2, next: None}}}
```
headの中身は↑
headはオブジェクトでnextは再帰的構造
単純に入力としてリストが与えられているわけではなかった

Choose a reason for hiding this comment

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

ズレたことを言ってたらすいませんが、リストではなく連結リストというデータ構造で、問題文の上の方でコメントアウトされている "class ListNode: ..."の部分の形で定義されています。授業でやられてるとのことですが、こんな感じ https://qiita.com/tsudaryo1715/items/12c4848028716ab015bb でノード同士を数珠繋ぎにしていったものになっています。

Copy link
Owner Author

Choose a reason for hiding this comment

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

すごく助かります!参照できる記事の提示もありがとうございます。ここら辺の記憶が曖昧になっていたので復習することにします

メモ:stdoutは標準出力の意味

(https://www.youtube.com/watch?v=uyd5vc0TZmA)を見た
以下は動画内のコード
```python
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
res = head

while head and head.next:
if head.val == head.next.val:
head.next = head.next.next
else:
head = head.next

return res

```

解法は前に授業で学んだことがあったため初見で解きたかった
headは繋ぐ場所を変えたらコード内の全てのheadが変わるの?
ここら辺勉強してみるとpythonは参照渡し(call by reference)?という話が出てきた
公式ドキュメントによると参照渡しはないそう
(https://qiita.com/aka-nse/items/ad8b6d487ed5f93ccf21)より
オブジェクトがミュータブルかイミュータブルかというのが重要な気がする

「変数に新たなオブジェクトそのものが代入されるときには、これまでの参照先から変わって新たなオブジェクトが作られた場所を参照するようになる。
で実務的には問題ないはず。」
(https://qiita.com/ponnhide/items/cda0f3f7ac88262eb31e)より

「immutableオブジェクトは変更できない は、既にメモリ上作成されていた元オブジェクトに対して変更することができないということになる」
「元となるデータを保持しているオブジェクト自体は変更されず、新しいオブジェクトを生成し、そちらを参照するのがimmutableオブジェクト、
データを保持しているオブジェクトそのものの値を変更できるのがmutableオブジェクトとなる。ただ、tupleのように複数のオブジェクトによって
構成されているようなオブジェクトは、immutableであっても内部のオブジェクトがmutableの場合、そのオブジェクト自体の値の変更は可能。」
(https://qiita.com/kojikawamura/items/50a7d1d426c12a8c702b)より

ここまで学んで何となく分かってきた
動画内のコードで res = headはresもheadも同じ中身のあるアドレスを参照している。
headの中身を編集しているが、headに新たなオブジェクトを代入しているわけではないので、アドレスは変更されない。
そのため最後のresは編集されたheadの中身と同じ。

オブジェクトの定義が気になったので公式ドキュメントを調べた。
「Python における オブジェクト (object) とは、データを抽象的に表したものです。Python プログラムにおけるデータは全て、オブジェクトまたはオブジェクト間の関係として表されます。
(ある意味では、プログラムコードもまたオブジェクトとして表されます。これはフォン・ノイマン: Von Neumann の "プログラム記憶方式コンピュータ: stored program computer" のモデルに適合します。)
すべてのオブジェクトは、同一性 (identity)、型、値をもっています。 同一性 は生成されたあとは変更されません。これはオブジェクトのアドレスのようなものだと考えられるかもしれません。
'is' 演算子は2つのオブジェクトの同一性を比較します。 id() 関数は同一性を表す整数を返します。」
(https://docs.python.org/ja/3.6/reference/datamodel.html)

xなどの変数はオブジェクトで”1”などの数字は値?

他の人のgitを見ていたが動画内のコードがシンプルで学んだことのある解法と同じためそっちを採用する

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

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

step3
1回目 1分8秒
2回目 52秒
3回目 53秒

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

while head and head.next is not None:
if head.val == head.next.val:

Choose a reason for hiding this comment

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

ご存じだったらすいませんが、僕もこれを解いた時に同じ書き方をしていて
(node and node.next) is not None:
の意になるのかなと思って同じ形で書いていたのですが、実は
(node) and (node.next is not None):
の意になっているらしく、きちんと書きたいときは
node is not None and node.next is not None:
と書くそうです。

また、後で訂正されていますがheadは固定して別のポインタを走査するのが自然です。

Copy link
Owner Author

Choose a reason for hiding this comment

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

勘違いしていました。後々やらかしそうなので指摘していただいたように、きちんと書くことにします。
ありがとうございます!

head.next = head.next.next
else:
head = head.next

return result
```

今更だけど計算量も求めていくものなのかな
コーディング面接対策もふまえて時間計算量と空間計算量の2つを求める

時間計算量はO(N)
Nはlinkedlistのnodeの数

空間計算量はO(1)
他に配列使ってるわけじゃないから1つだけ

以下はレビューを参考に修正したコード
headは先頭のノードの感覚があるのでwhileの中で動かすのはnodeだけにした
```python
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
result = node = head

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

return result
```