-
Notifications
You must be signed in to change notification settings - Fork 0
206. Reverse Linked List #19
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,152 @@ | ||
| # 206. Reverse Linked List | ||
| * 問題: https://leetcode.com/problems/reverse-linked-list/ | ||
| * 言語: Python | ||
|
|
||
| ## Step1 | ||
| * 単純に `node.next = node` とすると循環参照となり、TLE | ||
| * 1つの一時変数に `node.next` を退避しても循環参照となる | ||
| * 20分ほどWAで手が止まって5分経ったので正答を見る | ||
|
|
||
| ### 正答 | ||
| ```py | ||
| class Solution: | ||
| def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| prev = None | ||
| node = head | ||
|
|
||
| while node: | ||
| node_next = node.next | ||
| node.next = prev | ||
| prev = node | ||
| node = node_next | ||
|
|
||
| return prev | ||
| ``` | ||
| * 時間計算量: $O(n)$ | ||
| * 空間計算量: $O(1)$ | ||
| * ひとつ前、現在、ひとつ後のノードを保持する変数を使う | ||
| * ひとつ後のノードを一時変数 `next_temp` に退避してから、現在のノードのひとつ後のノードへのポインタをひとつ前のノードで更新 | ||
| * ひとつ前のノードを現在のノードで更新 | ||
| * 現在のノードを次のノードで更新 | ||
| * スタックと再帰を使った方法もありそう | ||
|
|
||
| ## Step2 | ||
| ### 他の人のコードを読む | ||
| * 典型コメント: https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.x5w37bodndgj | ||
| * https://github.com/TORUS0818/leetcode/pull/9 | ||
| - Python | ||
| - 繋ぎ替え、スタックとループ、再帰 | ||
| - スタックとループの方法では、新たにノードを生成しているので空間計算量が増える | ||
| - 一番わかりやすい気がする | ||
| - ```py | ||
| class Solution: | ||
| def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| if not head: | ||
| return head | ||
|
|
||
| node = head | ||
| visited_nodes = [] | ||
| while node: | ||
| visited_nodes.append(node.val) | ||
| node = node.next | ||
|
|
||
| reversed_head = ListNode(visited_nodes.pop(), None) | ||
|
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_headを作って、visited_nodesからpopする処理は全てwhileループの中でやると、似た処理が1箇所にまとまるので、個人的には好きです。 |
||
| reversed_node = reversed_head | ||
| while visited_nodes: | ||
| reversed_node.next = ListNode(visited_nodes.pop(), None) | ||
| reversed_node = reversed_node.next | ||
|
|
||
| return reversed_head | ||
| ``` | ||
| - 再帰 | ||
| - 現在のノードの次のノードから始まる部分リストを再帰的に反転 | ||
| - 次のノードのnext `node.next.next` を現在のノードに付け替え | ||
| - 現在のノードのnext `node.next` を `None` にする | ||
| - ```py | ||
| class Solution: | ||
| def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| if not head or not head.next: | ||
| return head | ||
|
|
||
| new_head = self.reverseList(head.next) | ||
| head.next.next = head | ||
| head.next = None | ||
| return new_head | ||
| ``` | ||
| - 再帰 | ||
| - 逆順になった先頭と末尾を戻すヘルパー関数を使う方法 | ||
| - ```py | ||
| class Solution: | ||
| def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| def reverse_list_helper(node): | ||
| if not node: | ||
| return None, None | ||
| if not node.next: | ||
| return node, node | ||
| node_next = node.next | ||
| node.next = None | ||
| reversed_head, reversed_tail = reverse_list_helper(node_next) | ||
| reversed_tail.next = node | ||
| return reversed_head, node | ||
|
|
||
| reversed_head, _ = reverse_list_helper(head) | ||
| return reversed_head | ||
| ``` | ||
| - cf. https://discord.com/channels/1084280443945353267/1231966485610758196/1239417493211320382 | ||
| * https://github.com/goto-untrapped/Arai60/pull/27/ | ||
| - Java | ||
| - 再帰 | ||
| - 先頭から自分まで逆順にしたものを次のノードに渡して、全部が逆順になったものを返してもらう | ||
| - 前から順番に付け替えていく | ||
| - ```java | ||
| class Solution { | ||
| ListNode reverseListHelper(ListNode reversed, ListNode rest) { | ||
| if (rest == null) { | ||
| return reversed; | ||
| } | ||
| ListNode rest_tail = rest.next; | ||
| rest.next = reversed; | ||
| return reverseListHelper(rest, rest_tail); | ||
| } | ||
|
|
||
| public ListNode reverseList(ListNode head) { | ||
| return reverseListHelper(null, head); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### 読みやすく書き直したコード | ||
| ```py | ||
| class Solution: | ||
| def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| reversed_head = None | ||
| rest = head | ||
|
|
||
| while rest: | ||
| rest_tail = rest.next | ||
| rest.next = reversed_head | ||
| reversed_head = rest | ||
| rest = rest_tail | ||
|
|
||
| return reversed_head | ||
| ``` | ||
|
|
||
| ## Step3 | ||
| ```py | ||
| class Solution: | ||
| def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| reversed_head = None | ||
| rest = head | ||
|
|
||
| while rest: | ||
| rest_tail = rest.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.
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. 参考まで、私は previous = None
node = headで初期化していました。これだと最終的に |
||
| rest.next = reversed_head | ||
| reversed_head = rest | ||
| rest = rest_tail | ||
|
|
||
| return reversed_head | ||
| ``` | ||
| * 解答時間 | ||
| - 1回目: 1:16 | ||
| - 2回目: 1:15 | ||
| - 3回目: 1:12 | ||
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.
next_node のほうが語順が自然だと思います。