From a84e48b52061b60804799abfe1b2a4a00eeed6ac Mon Sep 17 00:00:00 2001 From: Taito Ohsumi Date: Mon, 9 Dec 2024 14:49:20 +1100 Subject: [PATCH 1/3] Add 206. Reverse Linked List.md --- 206. Reverse Linked List.md | 171 ++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 206. Reverse Linked List.md diff --git a/206. Reverse Linked List.md b/206. Reverse Linked List.md new file mode 100644 index 0000000..9bdf4a7 --- /dev/null +++ b/206. Reverse Linked List.md @@ -0,0 +1,171 @@ +# step 1 +stackを用いるものと、そのままリストを辿っていくものを思いついたので実装した。 +再帰でもできるが、nodeの最大数(5000)がpythonのrecursion limit(1000)を超えるので、 +実装はしなかった。 + +stackを用いるもの + +「stackの末尾からノードを取ってきて、後ろに繋いでいけば逆順になります」はわかりやすいと思う。 + +nodeという変数を二つのwhile文で使い回してしまっているのが若干気持ち悪い。 +stackにノードを入れるときと、ノードを取り出すときとで、どちらも今注目しているノードくらいの意味で +nodeという変数を使っているため、これくらいなら許容範囲かと判断した。後半のwhile文ではnodeはなくても良いかも。 + +- time complexity: O(n) +- space complexity: O(n) (auxiliary space: O(n)) +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + stack = [None] + node = head + while node is not None: + stack.append(node) + node = node.next + + dummy_head = ListNode() + tail = dummy_head + while stack: + node = stack[-1] + stack.pop() + + tail.next = node + tail = tail.next + return dummy_head.next +``` + +そのままリストを辿る解法 + +- time complexity: O(n) +- space complexity: O(n) (auxiliary space: O(1)) + +previousを返すのが少し気持ち悪い。nodeに注目していたのに、返すものがpreviousであることに不整合を感じる。 +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + previous = None + node = head + while node is not None: + next_node = node.next + + node.next = previous + previous = node + node = next_node + + return previous +``` +# step 2 +- https://github.com/katataku/leetcode/pull/7/files + - 再帰の解法が書かれている + - 後ろからひっくり返していく解法(現在注目しているlistの先頭を引数に取り、そのリストを逆順にしたリストの先頭と末尾を返す) + - 先頭ノードを付け替えていく解法(現在注目しているlistの先頭と、逆順にしたlistのheadを引数に取り、オリジナルの先頭を逆順にしているリストの先頭にくっつける解法) +- https://github.com/konnysh/arai60/pull/7 + - previous, nextの命名に関して、前後というのは作業者が見ているものに対しての相対的な位置でしかなく、真にその変数が持つ性質を反映したものではない。その変数に何を期待するかを命名に入れた方がいい。previousだったら「構築してるノードの先頭」で、nextは「未処理ノードの先頭」みたいな感じ。そうすればstep1でpreviousを返すという違和感を解消できる。 + + +Iterative solution without stack +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + reversed_head = None + node = head + + while node is not None: + next_node = node.next + node.next = reversed_head + reversed_head = node + node = next_node + + return reversed_head +``` + +Iterative solution with stack +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + stack = [None] + node = head + while node is not None: + stack.append(node) + node = node.next + + reversed_dummy_head = ListNode() + reversed_tail = reversed_dummy_head + while stack: + node = stack[-1] + stack.pop() + + reversed_tail.next = node + reversed_tail = reversed_tail.next + return reversed_dummy_head.next +``` + +Reversive solution (後ろからひっくり返す) +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + def reverse_list_helper( + head: ListNode | None + ) -> Tuple[ListNode | None, ListNode | None]: + if head is None: + return None, None + if head.next is None: + return head, head + + reversed_head, reversed_tail = reverse_list_helper(head.next) + reversed_tail.next = head + + reversed_tail = reversed_tail.next + reversed_tail.next = None + return reversed_head, reversed_tail + return reverse_list_helper(head)[0] +``` + +Recursive solution (先頭ノードを付け替える) +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + def reverse_list_helper( + head: ListNode | None, + reversed_head: ListNode | None) -> ListNode | None: + if head is None: + return reversed_head + next_head = head.next + head.next = reversed_head + reversed_head = head + return reverse_list_helper(next_head, reversed_head) + return reverse_list_helper(head, None) +``` + +inner functionのtype annotaionはpython3.10+のものとした。 +public APIとかではないのでつける必要はない気がした。 + +# step 3 +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + reversed_head = None + node = head + while node is not None: + next_node = node.next + node.next = reversed_head + reversed_head = node + node = next_node + return reversed_head +``` + +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + def reverse_list_helper(head): + if head is None: + return None, None + if head.next is None: + return head, head + reversed_head, reversed_tail = reverse_list_helper(head.next) + + reversed_tail.next = head + reversed_tail = reversed_tail.next + reversed_tail.next = None + return reversed_head, reversed_tail + return reverse_list_helper(head)[0] +``` \ No newline at end of file From 1c24ef1fa15e2002104cf08aaea4befb6a6a0deb Mon Sep 17 00:00:00 2001 From: Taito Ohsumi Date: Thu, 19 Dec 2024 12:20:12 +1100 Subject: [PATCH 2/3] Add step 4 --- 206. Reverse Linked List.md | 78 +++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/206. Reverse Linked List.md b/206. Reverse Linked List.md index 9bdf4a7..bd5d49a 100644 --- a/206. Reverse Linked List.md +++ b/206. Reverse Linked List.md @@ -168,4 +168,82 @@ class Solution: reversed_tail.next = None return reversed_head, reversed_tail return reverse_list_helper(head)[0] +``` + +# step 4 +コメントまとめ +- 大規模開発ではtype annotationを入れることが多い +- ListNode | NoneよりOptional[ListNode] のほうがよく見る +- ループの途中で仕事を引き継いだ時に、パズルとならないような変数名をつける + +stackを使う解法 +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + stack = [] + node = head + while node is not None: + stack.append(node) + node = node.next + + dummy_head = ListNode() + tail = dummy_head + while stack: + tail.next = stack.pop() + tail = tail.next + tail.next = None + return dummy_head.next +``` + +stackを使わないiterative +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + reversed_head = None + node = head + while node is not None: + next_node = node.next + node.next = reversed_head + reversed_head = node + node = next_node + return reversed_head +``` + +後ろから作るrecursiveな解法 +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + def reverse_list_helper( + head: Optional[ListNode] + ) -> Tuple[Optional[ListNode], Optional[ListNode]]: + if head is None: + return None, None + if head.next is None: + return head, head + tail_list = head.next + head_node = head + head_node.next = None + + reversed_head, reversed_tail = reverse_list_helper(tail_list) + reversed_tail.next = head_node + reversed_tail = reversed_tail.next + return reversed_head, reversed_tail + return reverse_list_helper(head)[0] +``` + +先頭を付け替えていくrecursiveな解法 +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + def reverse_list_helper( + head: Optional[ListNode], + reversed_head: Optional[ListNode] + ) -> Optional[ListNode]: + if head is None: + return reversed_head + tail_list = head.next + head.next = reversed_head + reversed_head = head + return reverse_list_helper(tail_list, reversed_head) + return reverse_list_helper(head, None) ``` \ No newline at end of file From ac63c1588211cb91fb91b37608cff64c7c7689de Mon Sep 17 00:00:00 2001 From: Taito Ohsumi Date: Sat, 1 Mar 2025 10:32:38 +1100 Subject: [PATCH 3/3] Add another solution --- 206. Reverse Linked List.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/206. Reverse Linked List.md b/206. Reverse Linked List.md index bd5d49a..9533718 100644 --- a/206. Reverse Linked List.md +++ b/206. Reverse Linked List.md @@ -246,4 +246,24 @@ class Solution: reversed_head = head return reverse_list_helper(tail_list, reversed_head) return reverse_list_helper(head, None) +``` + +stackに積むときにnodeのリンクをバラバラにする +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + node = head + stack = [] + while node is not None: + next_node = node.next + node.next = None + stack.append(node) + node = next_node + + dummy_head = ListNode() + node = dummy_head + while stack: + node.next = stack.pop() + node = node.next + return dummy_head.next ``` \ No newline at end of file