-
Notifications
You must be signed in to change notification settings - Fork 0
Create 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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,216 @@ | ||
| # step1 | ||
|
|
||
| 前回の問題と似ている(https://github.com/wanwan87/LeetCode_arai60/pull/3) | ||
|
|
||
| 今回は重複があったら重複のあった番号は全て削除する。 | ||
|
|
||
| 前回のコードを一回書いてみて、ループの条件かifの条件を見直せばOKかな? | ||
|
|
||
| そういえば、node.next = node.next.nextっていう処理って削除というよりも、重複を飛ばすという処理なのかな? | ||
| メモリ上には残っていそう。 | ||
|
|
||
| [1,2,3,3,4,4,5]のときに、前の問題の通りの解法だと 3に到達すると[1,2,3,4,4,5]になるので、3が自分自身が重複していたかどうかを判定する必要があるので | ||
| 1つ前の値も保持しておかないとダメかな? | ||
|
|
||
| 重複している時点で、valも次の値にすればいいのかな? | ||
|
|
||
| ```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 | ||
| if node.next is not None: | ||
| node.val = node.next.val | ||
| else: | ||
| node = node.next | ||
| return head | ||
| ``` | ||
|
|
||
| [1,2,3,3,4,4,5]は通ったが[1,1,1,2,3]のときに挙動がおかしいし、[1,2,3,3]みたいなときに自分が消せないから値を保持する方向か。 | ||
|
|
||
| 1巡目:ListNode{val: 1, next: ListNode{val: 1, next: ListNode{val: 1, next: ListNode{val: 2, next: ListNode{val: 3, next: None}}}}} | ||
|
|
||
| 2巡目:ListNode{val: 1, next: ListNode{val: 1, next: ListNode{val: 2, next: ListNode{val: 3, next: None}}}} | ||
|
|
||
| 3巡目:ListNode{val: 2, next: ListNode{val: 2, next: ListNode{val: 3, next: None}}} | ||
|
|
||
|
|
||
| 1つ前の値を保存して置く場合、以下のコードベースで考えた時に | ||
| ①のようにwhileの下にsave = node入れると、if文にsave.val == node.valで1週目で引っかかっちゃう(現在の値を比較しているだけ。) | ||
| ②のようにif elseをぬけたところでsaveを作って、if文をand save.val == node.valにしようかと思ったけど、if文の中でnode書き換えちゃってるから意味ないよね? | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| node = head | ||
| while node is not None and node.next is not None: | ||
| #①save =node | ||
| if node.val == node.next.val: | ||
| node.next = node.next.next | ||
| else: | ||
| node = node.next | ||
| #②save = node | ||
| return head | ||
| ``` | ||
|
|
||
| 時間かけすぎたので以下の回答を見る。curが今見ているノードで、preがcurの後ろを指している。 | ||
|
|
||
| https://qiita.com/KueharX/items/860d1c227ddb8cba0a61 | ||
|
|
||
| 最初考えていた1つ前の値を保持していく方針と同じだがコードに落とし込めないなあ。紙に書きだして、なんとなくイメージは湧いたぐらいで手を付けている気がするので次からもう少し具体化するところを意識してみる。けどstep2以降で意識するのでもいいのかな。 | ||
|
|
||
| >「自分で手作業でできる」「人間にやり方を説明して代わりにやってもらえる」「機械にやり方を説明して代わりにやってもらえる(おおまかに、これがコードが書けること)」の順で難しくなっていくので、より簡単なのができないのだとたぶん書けないのです。 | ||
|
|
||
| https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.7n6wwffw10hb | ||
|
|
||
|
|
||
| ```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: ListNode) -> ListNode: | ||
| if not head: | ||
| return | ||
| node = pre = ListNode(0) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. こちらのコメントをご参照ください。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. チームなどで取り決められたルールを前提として、読み手が理解できるような変数名を心がけます |
||
| node.next = cur = head | ||
| while cur.next: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. こちらのコメントをご参照ください。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ありがとうございます、スタイルガイドも読んでみます |
||
| nex = cur.next | ||
| if cur.val == nex.val: | ||
| while(nex.next and nex.val == nex.next.val): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Python では while 文等の条件式に () は付けないことが多いと思います。 |
||
| nex = nex.next | ||
| pre.next = cur = nex.next | ||
| if not cur: | ||
| return node.next | ||
| else: | ||
| pre,cur,nex = cur,nex,nex.next | ||
| return node.next | ||
| ``` | ||
|
|
||
| - listnode(0)はListnodeのスタート1個前のdummyを作っている。 | ||
| - nodeの今の値と次の値が一致したときに、nodeの次の値とまたその次の値を順にみていくので、連続一致する限りループを続けている。 | ||
| - ループを抜けたら、preのnextとcurを[1,1,1,2,3]であれば、一致しない2にする | ||
| - if not cur は curがNoneだった場合はListNodeの末尾のため、リターンして終了 | ||
| - そもそも一致しない場合は次に進める | ||
| - returnは最初にlistnode(0)を入れているので、node.nextを返す | ||
|
|
||
| # step2 | ||
| - 個人的には、while cur.next is not Noneにしたい | ||
| - cur.nextをnexに入れなおした理由はなんだろう? | ||
| - シンプルに読みやすか | ||
| - nextのほうがわかりやすいように思えるがnexの理由はあるのだろうか | ||
| - next.nextはなおさら分かりにくいか | ||
| - nextは組み込み関数がある.next()はこのコード上では使ってないのでいいが、上書きされてしまうらしい | ||
| - https://docs.python.org/ja/3/library/functions.html#next | ||
| - elseの中で次に進めている、1行で代入を書くと変数が増えた時に見にくそうだ | ||
| - ListNode(0,next=head)にしても良い | ||
| - Listnode(0)とListnode()はは同じ、デフォルト引数が指定されているから | ||
| - この場合、node.next = headの処理が必要 | ||
| - Listnode(0,head)でもよい。Listnode(next=head)でもよい | ||
|
|
||
| - 個人的には | ||
| - https://discord.com/channels/1084280443945353267/1195700948786491403/1197103115539841055 | ||
| - とりあえず流れを読んだ。手順を素直に書き起こしてからコードにしてコードの整理をしていた。 | ||
| - https://github.com/rimokem/arai60/pull/4/changes | ||
| - これも読みやすい | ||
| - https://github.com/hiro111208/leetcode/pull/4/changes#r3067679658 | ||
| - 変数名とかが整理されていて読みやすい。上のやつのとif,elseが逆になっているだけかな? | ||
|
|
||
| ```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]: | ||
| dummy = ListNode(0,next=head) | ||
| current = dummy | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. こちらのコメントをご参照ください。 |
||
| while current is not None and current.next is not None: | ||
| runner = current.next | ||
| if runner.next is not None and runner.val == runner.next.val: | ||
| dupulicated_val = runner.val | ||
| while runner is not None and dupulicated_val == runner.val: | ||
| runner = runner.next | ||
| current.next = runner | ||
| else: | ||
| current = current.next | ||
| return dummy.next | ||
| ``` | ||
|
|
||
| # step3 | ||
|
|
||
| step2までは、runnerのループ出た後、elseでのnodeの扱いが曖昧だったが図に書き起こしながら操作していって理解できて来た。 | ||
|
|
||
| ```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]: | ||
| dummy = ListNode(next=head) | ||
| node = dummy | ||
| while node is not None and node.next is not None: | ||
| runner = node.next | ||
| if runner.next is not None and runner.val == runner.next.val: | ||
| dupulicated_val = runner.val | ||
| while runner is not None and runner.val == dupulicated_val: | ||
| runner = runner.next | ||
| node.next = runner | ||
| else: | ||
| node = runner | ||
| return dummy.next | ||
| ``` | ||
|
|
||
| スムーズに解けるようになってきた。duplicatedのスペル間違えていた。 | ||
|
|
||
| ```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]: | ||
| dummy = ListNode(next=head) | ||
| node = dummy | ||
| while node is not None and node.next is not None: | ||
| runner = node.next | ||
| if runner.next is not None and runner.val == runner.next.val: | ||
| duplicated_val = runner.val | ||
| while runner is not None and duplicated_val == runner.val: | ||
| runner = runner.next | ||
| node.next = runner | ||
| else: | ||
| node = node.next | ||
| return dummy.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]: | ||
| dummy = ListNode(next = head) | ||
| node = dummy | ||
| while node is not None and node.next is not None: | ||
| runner = node.next | ||
| if runner.next is not None and runner.val == runner.next.val: | ||
| duplicated_val = runner.val | ||
| while runner is not None and runner.val == duplicated_val: | ||
| runner = runner.next | ||
| node.next = runner | ||
| else: | ||
| node = node.next | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 条件分岐の前で There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. これ自分は割とどっちでもいいかなと思いました。 runnerは値が重複した時の削除用としてifの条件分岐内でしか使われてないからです。 else内でnode.nextとすることで、削除は行わず次のノードに注目を移すんだなっていう意図が伝わる気もします
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ありがとうございます |
||
| return dummy.next | ||
| ``` | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pythonはリファレンスカウントとガベージコレクションを併用してます。
今回は飛ばしたノードはリファレンスカウントがゼロになるのでメモリ上からは消されます
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
node.next = node.next.next は、 node.next の参照先を node.next.next に変更する、という処理です。結果として、元々 node.next が参照していたノードは、どこからも参照されなくなります。結果、 @kitano-kazuki さんがおっしゃった処理が行われます。
Python の変数は、メモリ上にあるオブジェクトへの参照が格納されるという点に注意が必要です。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ありがとうございます、理解しました