-
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,97 @@ | ||||||||||||||||||||
| 問題文: https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/ | ||||||||||||||||||||
|
|
||||||||||||||||||||
| # step1: 何も見ないで書く(制限時間5分) | ||||||||||||||||||||
| - 時間計算量O(n)、空間計算量O(1) | ||||||||||||||||||||
| - 新井さんの解説を丸写しした。正直コードは読めていない。 | ||||||||||||||||||||
| - 小田さんが言うところの仕事の引継ぎという発想が欠けていることを痛感した。 | ||||||||||||||||||||
| ```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.next is not None and node.next.next is not None: | ||||||||||||||||||||
| if node.next.val == node.next.next.val: | ||||||||||||||||||||
| copy = 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. copyモジュールがあるので、copyという変数名は避けたほうがよいかもしれません。 |
||||||||||||||||||||
| while copy.next is not None and copy.next.val == copy.val: | ||||||||||||||||||||
| copy.next = copy.next.next | ||||||||||||||||||||
| node.next = copy.next | ||||||||||||||||||||
| else: | ||||||||||||||||||||
| node = node.next | ||||||||||||||||||||
| return dummy.next | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ``` | ||||||||||||||||||||
| # step2: コードを整える | ||||||||||||||||||||
| ## 2-1 | ||||||||||||||||||||
| - 毎回のループで引き継ぐもの | ||||||||||||||||||||
| 1. 重複無しのノード: このグループの末尾を`latest_unique`で保持。 | ||||||||||||||||||||
| 2. 重複未チェックのノード: このグループの先頭のノードは`latest_unique.next`。これがループの主役なので`checking`と名付けて保持。 | ||||||||||||||||||||
| - skip_duplicates()に入力エラー処理が必要か迷ったが、`None`が入力されることはないのでとりあえずこのまま。 | ||||||||||||||||||||
| ```python | ||||||||||||||||||||
| class Solution: | ||||||||||||||||||||
| def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||||||||||||||||||||
| def skip_duplicates(node): | ||||||||||||||||||||
| while node.next is not None and node.next.val == node.val: | ||||||||||||||||||||
| node.next = node.next.next | ||||||||||||||||||||
| return node.next | ||||||||||||||||||||
| dummy = ListNode(next = head) | ||||||||||||||||||||
| latest_unique = dummy | ||||||||||||||||||||
| checking = latest_unique.next | ||||||||||||||||||||
| while checking is not None and checking.next is not None: | ||||||||||||||||||||
| if checking.val != checking.next.val: | ||||||||||||||||||||
| latest_unique = checking | ||||||||||||||||||||
| else: | ||||||||||||||||||||
| latest_unique.next = skip_duplicates(checking) | ||||||||||||||||||||
| checking = latest_unique.next | ||||||||||||||||||||
| return dummy.next | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ``` | ||||||||||||||||||||
| ## 2-2 | ||||||||||||||||||||
| - 2-1のコードをさらに整理。参考にした議論はdiscordのリンクを保存してなかったので引用できないが、小田さんがいろいろ突っ込みを入れていて19個目のつっこみで条件式を色々と変形していたあたりを参考にした。 | ||||||||||||||||||||
|
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 | ||||||||||||||||||||
| class Solution: | ||||||||||||||||||||
| def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||||||||||||||||||||
| def skip_duplicates(node): | ||||||||||||||||||||
| while node.next is not None and node.next.val == node.val: | ||||||||||||||||||||
| node.next = node.next.next | ||||||||||||||||||||
| return node.next | ||||||||||||||||||||
| dummy = ListNode(next = head) | ||||||||||||||||||||
|
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. inner functionの定義の後には空行を入れたいなと思いましたが、好みかもしれません。 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.
同じように感じました |
||||||||||||||||||||
| latest_unique = dummy | ||||||||||||||||||||
| checking = latest_unique.next | ||||||||||||||||||||
| while checking is not None and checking.next is not None: | ||||||||||||||||||||
| if checking.val != checking.next.val: | ||||||||||||||||||||
| latest_unique = checking | ||||||||||||||||||||
| checking = latest_unique.next | ||||||||||||||||||||
| continue | ||||||||||||||||||||
| latest_unique.next = skip_duplicates(checking) | ||||||||||||||||||||
| checking = latest_unique.next | ||||||||||||||||||||
| return dummy.next | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ``` | ||||||||||||||||||||
|
|
||||||||||||||||||||
| # step3: ミスなく3回書く(制限時間10分) | ||||||||||||||||||||
| ```python | ||||||||||||||||||||
| class Solution: | ||||||||||||||||||||
| def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||||||||||||||||||||
| def skip_duplicates(node): | ||||||||||||||||||||
| while node.next is not None and node.next.val == node.val: | ||||||||||||||||||||
| node.next = node.next.next | ||||||||||||||||||||
| return node.next | ||||||||||||||||||||
|
Comment on lines
+81
to
+84
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を繋ぎかえていくのではなく、nodeを動かしていく方法のほうが分かりやすいかなと感じました。
Suggested change
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. 修正後の方がいいですね。手抜きして関数化する前のコードをそのまま関数のコードに流用しておりました。 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.
同感です。修正後の方が私も良いと思います。 |
||||||||||||||||||||
| dummy = ListNode(next = head) | ||||||||||||||||||||
|
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. PEP8ではキーワード引数への代入演算子の前後にはスペースを入れないことになっています。ご参考まで。
|
||||||||||||||||||||
| latest_unique = dummy | ||||||||||||||||||||
| checking = latest_unique.next | ||||||||||||||||||||
| while checking is not None and checking.next is not None: | ||||||||||||||||||||
| if checking.val != checking.next.val: | ||||||||||||||||||||
| latest_unique = checking | ||||||||||||||||||||
| checking = latest_unique.next | ||||||||||||||||||||
| continue | ||||||||||||||||||||
| latest_unique.next = skip_duplicates(checking) | ||||||||||||||||||||
| checking = latest_unique.next | ||||||||||||||||||||
|
Comment on lines
+85
to
+94
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.
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
def skip_duplicates(node: ListNode) -> Optional[ListNode]:
while node.next is not None and node.next.val == node.val:
node.next = node.next.next
return node.next
dummy = ListNode() # 確定済みリストの番兵
latest_unique = dummy # その末尾。常に latest_unique.next は None
checking = head # 未確定側の走査ポインタ
while checking is not None:
# 直後が別値 or 末尾ならユニーク
if checking.next is None or checking.val != checking.next.val:
latest_unique.next = checking # 確定側に連結
latest_unique = checking # 末尾を更新
checking = checking.next # 未確定側を先に進める
latest_unique.next = None # 不変条件: ここで切断
else:
# 重複ブロックは確定側に触れずスキップ
checking = skip_duplicates(checking)
return dummy.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.
一般にネストを浅くしたほうが読みやすくなる傾向があります。真偽を逆にして、ネストを浅くするとよいと思います。