From a29abedb99002677d68ca10fa939cf1ab134278f Mon Sep 17 00:00:00 2001 From: katataku Date: Tue, 19 Nov 2024 11:53:22 +0900 Subject: [PATCH] 206. Reverse Linked List.md --- 206. Reverse Linked List.md | 129 ++++++++++++++++++++++++++++++++++++ 1 file changed, 129 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..75da393 --- /dev/null +++ b/206. Reverse Linked List.md @@ -0,0 +1,129 @@ +URL: https://leetcode.com/problems/reverse-linked-list/description/ + +# Step 1 + +線形リストを順に辿るやり方と、再帰を使うやり方を思いついた。 + +- 実装時間: 10分 +- 時間計算量: O(n) +- 空間計算量: O(1) + +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + node = head + reversed_nodes = None + while node is not None: + next_node = node.next + node.next = reversed_nodes + reversed_nodes = node + node = next_node + return reversed_nodes +``` + +- 実装時間: 5分 +- 時間計算量: O(n**2) +- 空間計算量: O(1) + +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + def append_linked_list(head, node): + if head is None: + return node + current = head + while current.next is not None: + current = current.next + current.next = node + return head + + if head is None: + return None + reversed_tail = self.reverseList(head.next) + head.next = None + return append_linked_list(reversed_tail, head) +``` + +反転したリストの末尾を毎回求めているため計算量が増えた。計算量を削減するためのヘルパー関数を用いる再帰パターン。 + +- 実装時間: 5分 +- 時間計算量: O(n) +- 空間計算量: O(1) + +```python +class Solution: + # returns head node and last node + def _reverseListRecursive(self, head: Optional[ListNode]) -> Tuple[Optional[ListNode],Optional[ListNode]]: + if head is None: + return None, None + if head.next is None: + return head, head + reversed_head, reversed_last = self._reverseListRecursive(head.next) + reversed_last.next = head + head.next = None + return reversed_head, head + + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + return self._reverseListRecursive(head)[0] +``` + +# Step 2 + +- `reversed_nodes`の変数名について + - 指しているのはreverseしたリストの先頭ノード + - 複数の要素を持つ配列を指しているわけじゃなくてあくまで単一ノードを指している。 + - `reversed_head`がよさそう + +- 再帰で実装したパターン + - reverseListの末尾まで辿らなくても、元リストのnode.nextが末尾なことは問題からわかるので、計算しなくても良い。 + - https://github.com/tarinaihitori/leetcode/pull/6/files + +- 補助関数の関数名について + - Auxiliary や Helper などをつけて呼ばないことを想定しているとはっきりさせる + - 直接ユーザーが呼ぶことの想定されない内部関数で、引数が増やしてあるなどほとんど元と同じものの場合は、名前を、元の関数の名前 + Helper にするのは一つの選択肢でしょう。 + - https://github.com/hroc135/leetcode/pull/7/files#r1690169396 + +- 他の方のコードを見て見つけた別パターン + - いったんStackにすべてのNodeを積んで、逆順に繋いでいくパターン。 + - 再帰は2パターンある。 + - 後ろからひっくり返していく方法がある気がします。後ろからひっくり返ったものの頭と尻尾をもらって、そこに自分のを外して付け直します。 + - 僕はこっち。 + - `reverseListRecursive(current, previous *ListNode)`を使って、先頭ノードを付け替えていくパターン。 + +別パターンの再帰も実装してみる。 + +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + def reverseListHelper(current_head: Optional[ListNode], reversed_head: Optional[ListNode]) -> Optional[ListNode]: + if current_head is None: + return reversed_head + next_node = current_head.next + current_head.next = reversed_head + return reverseListHelper(next_node, current_head) + return reverseListHelper(head, None) +``` + +- 関数名はUpperCamel + - https://github.com/konnysh/arai60/pull/7/files#r1845471829 + - 本来は先頭も大文字だけど、周囲(Leetcodeで指定されている関数名)に合わせるために、先頭小文字の補助関数の名前をつける。 + +# Step 3 + +この再帰の書き方が綺麗に思った。再帰のオーバーヘッドや呼び出し回数上限に気を配る必要があるがこの書き方を選ぶ。 + +- 時間計算量: O(max(n,m)) +- 空間計算量: O(max(n,m)) + +```python +class Solution: + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + def reverseListHelper(current_head: Optional[ListNode], reversed_head: Optional[ListNode]) -> Optional[ListNode]: + if current_head is None: + return reversed_head + next_node = current_head.next + current_head.next = reversed_head + return reverseListHelper(next_node, current_head) + return reverseListHelper(head, None) +``` +