-
Notifications
You must be signed in to change notification settings - Fork 0
206. Reversed Linked List #8
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,176 @@ | ||
| # 206. Reverse Linked List | ||
|
|
||
| Given the head of a singly linked list, reverse the list, and return the reversed list. | ||
|
|
||
| Constraints: | ||
|
|
||
| The number of nodes in the list is the range [0, 5000]. | ||
| -5000 <= Node.val <= 5000 | ||
|
|
||
| ```Python3 | ||
| class ListNode: | ||
| def __init__(self, val=0, next=None): | ||
| self.val = val | ||
| self.next = next | ||
| ``` | ||
|
|
||
| ## Step1 | ||
|
|
||
| - ノードの数からstackに先頭から積んでいって | ||
| - 積み終わったらスタックから取り出していて連結リストを作る | ||
|
|
||
| ```Python3 | ||
| from collections import deque | ||
| class Solution: | ||
| def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| # Noneのチェックしなくても通りはする(好みの範囲?) | ||
| if not head: | ||
| return None | ||
|
|
||
| node = head | ||
| stack = deque() | ||
| while node is not None: | ||
| stack.append(node.val) | ||
| node = node.next | ||
|
|
||
| # 分岐を減らすために番兵を利用 | ||
| reverse_dummy = ListNode() | ||
| reverse_node = reverse_dummy | ||
| while stack: | ||
| val = stack.pop() | ||
| reverse_node.next = ListNode(val) | ||
| reverse_node = reverse_node.next | ||
| return reverse_dummy.next | ||
| ``` | ||
| - ネストしてはいないものの、ループが二つあるのが気になる。。。もっといいやり方ないかな。。。 | ||
|
|
||
| - 時間計算量: O(n) | ||
| - 空間計算量: O(n) | ||
|
|
||
| ## Step2 | ||
|
|
||
| - 手作業でやると考えた時に、一度stackに積むのは非効率 | ||
| - 手作業でやるならば:元の連結リストの先頭要素と同じ値の要素を作りそこを基準に、元の連結リストの要素に相当する要素を作って新しい反転させるリストの先頭に持っていく | ||
| - 新しいリストを作らず元のリストをそのままいじるやり方もありそう | ||
| ```Python3 | ||
| class Solution: | ||
| def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| original_node = head | ||
| # 前のループでの反転させたリストの先頭 | ||
| reverse_head = None | ||
| while original_node is not None: | ||
| reverse_head = ListNode(original_node.val, reverse_head) | ||
| original_node = original_node.next | ||
| return reverse_head | ||
| ``` | ||
|
|
||
| - https://github.com/t0hsumi/leetcode/pull/7#discussion_r1875385145 | ||
| - 渡されたリストを直接いじって繋ぎかえるパターン | ||
| - ひっくり返したリストの先頭、ひっくり返す前の先頭を持っておけばよし | ||
| - 手作業: | ||
| - 0. ひっくり返す前の先頭を保存(「元の要素」とする) | ||
| - 1. ひっくり返す前の先頭を次の要素に移動 | ||
| - 2. 「元の要素」をひっくり返す前の先頭に繋ぎ変え | ||
| - 3. ひっくり返す前の先頭を「元の要素」に更新 | ||
| - メモリ使用量は新しいリストを作らない分こっちの方が抑えられる | ||
| - ノード数の制約と引数で渡された連結リストを破壊的に変更するかどうかを考えると個人的には新しい反転リストを作る方法の方が好み | ||
| ```Python3 | ||
| class Solution: | ||
| def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| original_head = head | ||
|
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. head はリンクトリストの先頭を表すノードのため、変数名を変えたほうが良いかもしれません。ただ、今回は head の位置のノードを逆順のリンクトリストに繋ぎ変え、 head が残りの部分の先頭を表すノードになるため、そのままでも十分通じるかもしれません。 |
||
| reverse_head = None | ||
| while original_head is not None: | ||
| original_node = original_head | ||
| original_head = original_head.next | ||
| original_node.next = reverse_head | ||
| reverse_head = original_node | ||
| return reverse_head | ||
| ``` | ||
|
|
||
| - https://github.com/irohafternoon/LeetCode/pull/7#discussion_r2019076979 | ||
| - リンクを中心に見る | ||
| ```Python3 | ||
| class Solution: | ||
| def reverseList(self, head): | ||
| # reverse_head, head, original_nextのリンクの繋ぎ変え | ||
| reverse_head = None | ||
| while head: | ||
| original_next = head.next | ||
| head.next = reverse_head | ||
| reverse_head = head | ||
| head = original_next | ||
| return reevrse_head | ||
| ``` | ||
|
|
||
| - https://discord.com/channels/1084280443945353267/1231966485610758196/1239417493211320382 | ||
| - > 自分よりも下流を逆順にして、頭と尻尾の輪っかを渡してください | ||
| - お尻は下流に渡したノードになっているので省略可能 | ||
|
|
||
| - https://github.com/goto-untrapped/Arai60/pull/27#discussion_r1638693522 | ||
| - 下流に渡す時の選択肢 | ||
| - 1. 反転した上流と残りを下流に渡して全て反転してもらう(行きがけ) | ||
| - 2. 残りを渡してそこだけ反転したものを返してもらい(先頭と末尾があればよい)、それを利用して上流も反転(帰りがけ) | ||
|
|
||
| 1) | ||
| ```Python3 | ||
| class Solution: | ||
| def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| def reverse_helper(reversed_node: Optional[ListNode], rest_node: Optional[ListNode]) -> Optional[ListNode]: | ||
| if rest_node is None: | ||
| return reversed_node | ||
| next_rest = rest_node.next | ||
| rest_node.next = reversed_node | ||
| return reverse_helper(rest_node, next_rest) | ||
| return reverse_helper(None, head) | ||
| ``` | ||
|
|
||
| 2) | ||
| ```Python3 | ||
| class Solution: | ||
| def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| def reverse_helper(node: Optional[ListNode]) -> Tuple[Optional[ListNode], Optional[ListNode]]: | ||
| if node is None: | ||
| return None, None | ||
| if node.next is None: | ||
| return node, node | ||
| tail = node.next | ||
| node.next = None # reverseListを呼ぶ前にやっても後にやっても変わらなさそう(どういう違いがあるのかが言語化できなかった) | ||
| reversed_head, reversed_tail = reverse_helper(tail) | ||
| reversed_tail.next = node | ||
| return reversed_head, node | ||
| return reverse_helper(head)[0] | ||
| ``` | ||
|
|
||
| 2-1) 実はtailは不要(上でnode.next is Noneの時にnode, nodeと二つ同じものを返しているところに違和感を感じて気づく?) | ||
|
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. 不要でも渡したほうが読みやすい気はします。 |
||
| ```Python3 | ||
| class Solution: | ||
| def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| if head is None: | ||
| return None | ||
| if head.next is None: | ||
| return head | ||
| next_head = head.next | ||
| head.next = None | ||
| reversed_head = self.reverseList(next_head) | ||
| next_head.next = head | ||
| return reversed_head | ||
| ``` | ||
| - https://github.com/resumit30minutes/leetcode-arai60-practice/pull/8/files#diff-56cce9af784f5c572f0706e03269e28af28f8aabbface21c32e6199d6400c657 | ||
| - https://github.com/quinn-sasha/leetcode/pull/7#discussion_r1948355100 | ||
| - stackを利用する場合でもNodeのまま次へのつながりを切ってstackに積むやり方もあり | ||
|
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. 一応、この問題の出題意図は、LinkedList でお手玉ができますかということかと思うので、これは出題意図には沿っていないだろうと推測します。 |
||
| - 値をstackに積んでからstackからひとつつづ取り出して新しくNodeを作るよりメモリ使用量は少なくなりそうだが、ノード数の制約から値をstackに積む方が好み | ||
|
|
||
| - https://github.com/nanae772/leetcode-arai60/pull/8/files#r2324800451 | ||
| - 再帰の上限を上げるのは好ましくないかも | ||
|
|
||
| # Step3 | ||
|
|
||
| ```Python3 | ||
| class Solution: | ||
| def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| reversed_head = None | ||
| while head is not None: | ||
| reversed_head = ListNode(head.val, reversed_head) | ||
|
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.
|
||
| head = head.next | ||
| return reversed_head | ||
| ``` | ||
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.
スタックとして使うのであれば list で十分だと思います。一般に、同じ目的に使えるデータ構造が複数ある場合、その中で一番実装が軽いものを選ぶことが多いように思います。