diff --git a/82. Remove Duplicates from Sorted List II.md b/82. Remove Duplicates from Sorted List II.md new file mode 100644 index 0000000..41b9ff5 --- /dev/null +++ b/82. Remove Duplicates from Sorted List II.md @@ -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) + node.next = cur = head + while cur.next: + nex = cur.next + if cur.val == nex.val: + while(nex.next and nex.val == nex.next.val): + 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 + 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 + return dummy.next +```