diff --git a/206. Reverse Linked List/206. Reverse Linked List.md b/206. Reverse Linked List/206. Reverse Linked List.md new file mode 100644 index 0000000..d57cce7 --- /dev/null +++ b/206. Reverse Linked List/206. Reverse Linked List.md @@ -0,0 +1,226 @@ +問題文: https://leetcode.com/problems/reverse-linked-list/description/ + +# step1: 何も見ないで書く(制限時間5分) +- ノードを前から順に積み上げ、積み上げたノードを上から順につなぎなおせば逆順にできる。 + - 時間計算量O(n), 空間計算量O(n)。 + - ループで実装するのが一番簡単な気がする。 +- 再帰を使ったらスタック無しで実装できそうだけど、どんな手順になるかはすぐに思いつかない。 + - 妥協案として、ノードをスタックしてから再帰的に逆順のリストを作る方法にした。 + +## 1-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 reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + if head is None or head.next is None: + return head + + node = head + reversed_nodes = [None] + while node is not None: + reversed_nodes.append(node) + node = node.next + + reversed_head = reversed_nodes.pop() + node = reversed_head + while reversed_nodes: + node.next = reversed_nodes.pop() + node = node.next + + return reversed_head + +``` + +## 1-2: 再帰 +- 行きがけの再帰で実装した。帰りがけへの書き換えも可能(reversed_headも関数内でpopして作り、popしたノードをreturnする)だが省略する。 +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + def get_reversed_list(node, stacked_nodes): + if not stacked_nodes: + return None + node.next = stacked_nodes.pop() + get_reversed_list(node.next, stacked_nodes) + + if head is None or head.next is None: + return head + + node = head + reversed_nodes = [None] + while node is not None: + reversed_nodes.append(node) + node = node.next + + reversed_head = reversed_nodes.pop() + get_reversed_list(reversed_head, reversed_nodes) + return reversed_head + +``` + +# step2: 他の人を参考にコードを整える・コメントを予測する +## 典型コメント集 +https://discord.com/channels/1084280443945353267/1231966485610758196/1239417493211320382 +- 再帰で繋ぎ変えるときの手順について。実際の処理はループの方が簡単だと思うが、再帰の方が手順を考える訓練になると感じる。 + +https://github.com/TORUS0818/leetcode/pull/9/files +- 再帰での繋ぎ変えを検討している。繋ぎ変えの処理で変数がお手玉のように入れ替わるので読みにくい。 + +https://github.com/goto-untrapped/Arai60/pull/27/files#diff-46bd7fda9ce7231cf7f817c639106d9dda840171202428e02291f5d39c172801 +- ループを使った繋ぎ変え。これもお手玉っぽさがあるので、ループか再帰かよりも仕事の引継ぎという発想で処理を組み立てられているかが重要そう。 + +https://github.com/katataku/leetcode/pull/7/files +- 再帰を2通り試している。行きがけだと元のリストの先頭から繋ぎ変えていく処理で、帰りがけだと元のリストの末尾から繋ぎ変える処理になる。 + +https://github.com/tarinaihitori/leetcode/pull/6/files +- 通常のpython環境で再帰を使用できるかを再帰回数の上限という点から検討している。再帰を使うときに何を気にすればいいのかわかっていないので参考になった。 + +https://github.com/quinn-sasha/leetcode/pull/7/files#r1948355100 +- スタックに積む際にノードのリンクを切る方法。私のstep1は単にリストをスタックに入れただけでリンクは切っていなかったため、逆順リストの最後尾の処理が少し面倒になっていた。これなら処理がシンプル。 + +https://discord.com/channels/1084280443945353267/1355246975309844550 +- リンクの逆転の仕方は実は3通りくらいあるという話。 + + +## 直近のコード +https://github.com/docto-rin/leetcode/pull/7/files#r2403779253 +- 入力されるリストを壊してもいいのかどうか。どう判断すべきか分からない。全ノードを逆転させることがわかっているから、入力を壊してもすぐに復元できそうな気がする。 + +https://github.com/MasukagamiHinata/Arai60/pull/3#discussion_r2393826274 +-「一人で手でできる」→「シフトを組んで複数人でできる」→「機械にやらせられる」の順で仕事が難しくなるという話。 +- 私は「一人の手作業」で止まりがちだった。再帰に苦手意識があるのも「複数人でシフトを組む」水準まで考える癖がないことが大きな原因になっていそう。 + +https://github.com/kt-from-j/leetcode/pull/7#discussion_r2393410573 +- 練習の進め方について。私も可能な限りログを調べがちなのでこれからはスピードも意識する。 +- 私の場合、問題を解くのに締め切りを設けてないのが良くない気がするので、着手してから2日以内に終わらせるなど自分で締め切りを設ける。 + +https://github.com/nanae772/leetcode-arai60/pull/8/files#r2324800451 +- 再帰の上限をいじったときに生じうる問題について。ひらがなの読み書きだけ練習していると、こういう感覚は身につかないのだろう。 + +## 2-1: ループ +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + if head is None or head.next is None: + return head + + node_in_original = head + reversed_nodes = [] + while node_in_original is not None: + residual_head = node_in_original.next + node_in_original.next = None + reversed_nodes.append(node_in_original) + node_in_original = residual_head + + dummy = ListNode(None) + node_in_reverse = dummy + while reversed_nodes: + node_in_reverse.next = reversed_nodes.pop() + node_in_reverse = node_in_reverse.next + return dummy.next + +``` + +## 2-2: 行きがけの再帰(前から逆順にしていく) +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + def reverse_list_helper(disassembling_head: Optional[ListNode],reversed_head: Optional[ListNode]) -> Optional[ListNode]: + if disassembling_head is None: + return reversed_head + node = disassembling_head + disassembling_head = disassembling_head.next + node.next = reversed_head + reversed_head = node + return reverse_list_helper(disassembling_head, reversed_head) + + return reverse_list_helper(head, None) + +``` + +## 2-3: 帰りがけの再帰(後ろから逆順にしていく) +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + def reverse_list_helper(node: Optional[ListNode]) -> Tuple[Optional[ListNode], Optional[ListNode]]: + if node is None: + return None, None + if node.next is None: + return node, node + reversed_head, reversed_tail = reverse_list_helper(node.next) + node.next = None + reversed_tail.next = node + reversed_tail = reversed_tail.next + return reversed_head, reversed_tail + + reversed_head, reversed_tail = reverse_list_helper(head) + return reversed_head + +``` + +# step3: 3回連続ミスなしで書く(制限時間10分) + +## 3-1: ループ +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + if head is None or head.next is None: + return head + + node = head + reversed_nodes = [] + while node is not None: + residual_head = node.next + node.next = None + reversed_nodes.append(node) + node = residual_head + + dummy = ListNode(None) + reversed_tail = dummy + while reversed_nodes: + reversed_tail.next = reversed_nodes.pop() + reversed_tail = reversed_tail.next + return dummy.next + +``` + +## 3-2: 行きがけの再帰 +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + def reverse_list_helper(separating_head, reversed_head): + if separating_head is None: + return reversed_head + + node = separating_head + separating_head = separating_head.next + node.next = reversed_head + reversed_head = node + return reverse_list_helper(separating_head, reversed_head) + + return reverse_list_helper(head, None) + +``` + + +## 3-3: 帰りがけの再帰 +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + def reverse_list_helper(node): + if node is None or node.next is None: + return node, node + + reversed_head, reversed_tail = reverse_list_helper(node.next) + node.next = None + reversed_tail.next = node + reversed_tail = reversed_tail.next + return reversed_head, reversed_tail + + reversed_head, _ = reverse_list_helper(head) + return reversed_head + +```