From b5621573b9687f15a39806a5e69ac05669975fcb Mon Sep 17 00:00:00 2001 From: katataku Date: Mon, 11 Nov 2024 10:25:23 +0900 Subject: [PATCH 1/2] 82. Remove Duplicates from Sorted List II --- 82. Remove Duplicates from Sorted List II.md | 127 +++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 82. Remove Duplicates from Sorted List II.md 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..bb99ff3 --- /dev/null +++ b/82. Remove Duplicates from Sorted List II.md @@ -0,0 +1,127 @@ + +URL: https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/description/ + +# Step 1 + +- 実装時間: 15+3分 +- 時間計算量: O(n) +- 空間計算量: O(1) +- 問題を見て、「ループで実装する方法」と「再帰で実装する方法」の二種類を思いついた。ループで解いてみたが15分で解けなかったので、再帰で実装。 + +```python +class Solution: + def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: + if head is None: + return None + if head.next is None: + return head + if head.val != head.next.val: + head.next = self.deleteDuplicates(head.next) + return head + target_val = head.val + node = head + while node is not None and node.val == target_val: + node = node.next + return self.deleteDuplicates(node) +``` + +↓が時間切れで解き切れなかったループの残骸。入力`[1,1]`でエラーになる。 + +```python +class Solution: + def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: + if head is None: + return None + node = head + dummy = ListNode(0, head) + pre = dummy + while node is not None: + if node.next is not None and node.val == node.next.val: + target_val = node.val + while node is not None and node.val == target_val: + node = node.next + continue + pre.next = node + pre = node + node = node.next + return dummy.next +``` + +# Step 2 + +- 再帰はオーバーヘッドがあるので避けるべきだと思っていたが、別の観点もある。 + - 再帰でない記述だと入力にループがある場合無限ループになるのに対して、再帰で書くと`RecursionError`を投げてくれるのでこちらのほうがよいという考えもありますね。 +https://docs.python.org/3/library/exceptions.html#RecursionError + +- 命名について + - `sentinel`という命名があることを知った。 + - `target_val`も意味のあまりない命名だと気づいた。`value_to_remove`を使う。 + - `val`もvalueの略語なので、避ける。 + +- ループでの実装について。 + - 「重複していて取り除く」のか「重複していないから取り除かない」のかの二種類の状態がある。 + - 「重複していないから取り除かない」でearly returnするとみやすい。 + - `pre`と`node`の2変数は不要。1つの変数で管理できる。 + +```python +class Solution: + def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: + if head is None: + return None + dummy = ListNode(0, head) + node = dummy + while node.next is not None: + if node.next.next is None or node.next.val != node.next.next.val: + node = node.next + continue + value_to_remove = node.next.val + while node.next is not None and node.next.val == value_to_remove: + node.next = node.next.next + return dummy.next +``` + +- `is_duplicated`などのフラグを使うと、whileループのネストを避けることができ、O(n)ということが伝わりやすい。 + - `Optional[int]`という方法も。 + - https://discord.com/channels/1084280443945353267/1226508154833993788/1246022270984392724 + +```python +class Solution: + def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: + dummy = ListNode(0, head) + node = dummy + deleting_number = None + while node.next is not None: + if deleting_number is not None and node.next.val == deleting_number: + node.next = node.next.next + continue + if node.next.next is not None and node.next.val == node.next.next.val: + deleting_number = node.next.val + continue + deleting_number = None + node = node.next + + return dummy.next +``` + +# Step 3 + +- 時間計算量: O(n) +- 空間計算量: O(1) + +```python +class Solution: + def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: + sentinel = ListNode(0, head) + node = sentinel + deleting_number = None + while node.next is not None: + if deleting_number is not None and node.next.val == deleting_number: + node.next = node.next.next + continue + if node.next.next is not None and node.next.val == node.next.next.val: + deleting_number = node.next.val + continue + deleting_number = None + node = node.next + return sentinel.next +``` From ef51843eeb8990cf3f0bb6e7971bc7c41fec2eb0 Mon Sep 17 00:00:00 2001 From: katataku Date: Tue, 12 Nov 2024 12:10:18 +0900 Subject: [PATCH 2/2] =?UTF-8?q?pre=E3=82=92=E4=BD=BF=E3=81=A3=E3=81=9F?= =?UTF-8?q?=E3=82=84=E3=82=8A=E6=96=B9=E3=81=A7=E3=80=81=E8=BF=BD=E5=8A=A0?= =?UTF-8?q?=E3=81=A7=E8=A7=A3=E3=81=84=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 82. Remove Duplicates from Sorted List II.md | 22 ++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/82. Remove Duplicates from Sorted List II.md b/82. Remove Duplicates from Sorted List II.md index bb99ff3..f110fe3 100644 --- a/82. Remove Duplicates from Sorted List II.md +++ b/82. Remove Duplicates from Sorted List II.md @@ -125,3 +125,25 @@ class Solution: node = node.next return sentinel.next ``` + +# Step 4 + +preを使った書き方についてコメントをいただいたので、一晩おいた後に書いてみた。 + +```python +class Solution: + def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: + sentinel = ListNode(0, head) + pre = sentinel + node = head + while node is not None: + if node.next is None or node.val != node.next.val: + pre = pre.next + node = node.next + continue + value_to_remove = node.val + while node is not None and node.val == value_to_remove: + node = node.next + pre.next = node + return sentinel.next +```