-
Notifications
You must be signed in to change notification settings - Fork 0
Add 206. Reverse Linked List.md #7
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,269 @@ | ||
| # 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() | ||
|
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.
|
||
|
|
||
| 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であることに不整合を感じる。 | ||
|
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. 仕事をループの途中で引き継いだとしましょう。 これが node と 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, | ||
|
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. Optional[ListNode] のほうがよく見ますかね。 |
||
| 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とかではないのでつける必要はない気がした。 | ||
|
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. 拝見して、僕も気になったので調べてみました。
https://google.github.io/styleguide/pyguide.html#3191-general-rules 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. 最近では、ある程度大規模な開発になると型を書いているように思いますね。 |
||
|
|
||
| # 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) | ||
|
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.next を別の変数に入れて、
Owner
Author
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. コメントありがとうございます。
|
||
|
|
||
| reversed_tail.next = head | ||
| reversed_tail = reversed_tail.next | ||
| 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) | ||
| ``` | ||
|
|
||
| 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 | ||
| ``` | ||
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.
自分はstackにNoneを入れるのが気になりました。反転した後の末尾のnextをNoneにするためだと思うのですが、その意図を汲むのが難しいように思います。素直に2つ目のwhileを抜けた後にNoneを代入するので良いかなと思いました。