-
Notifications
You must be signed in to change notification settings - Fork 0
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?
Conversation
return reverseListHelper(head, None) | ||
``` | ||
|
||
- 関数名はUpperCamel |
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.
あ、関数名をUpperCamelにするのはC++のケースで、言語やコーディング規約によって変わってくると思います。Pythonのコーティング規約のPEP8だと全て小文字のsnake_caseらしいです。
https://peps.python.org/pep-0008/#function-and-variable-names
Pythonに詳しくないので、他の有名な規約とかもあるかもしれませんが、とりあえず知ってるものだけ挙げときます。
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.
ありがとうございます!
以下自分の調べたメモ:
- googleのstyleguideでもlower_with_under()
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.
個人的には再帰なのかループなのかという書き方の違いよりかは、この関数が破壊的なのか非破壊的なのかの方が興味があります。
|
||
```python | ||
class Solution: | ||
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: |
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.
なんか全体的に命名が分かりづらいなと思いました。
current_head
のcurrentには現在注目しているくらいの意味しかなくて、reversed_head
とどう違うんだろうみたいな感想を持ちました。あとは、reversed_head
とありますが、current_head
もreverseしてるじゃんみたいな気持ちになりました。
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.
ありがとうございます。
日本語で説明してみると、それぞれ
- 「元のリストを順番に見ていくための先頭ノード」
- 「これから逆順のリストを作っていく。その作業の途中の先頭ノード」
が言いたいことなので、ichikaさんの例のようにoriginal
を含めるべきだと気づきました。
|
||
この再帰の書き方が綺麗に思った。再帰のオーバーヘッドや呼び出し回数上限に気を配る必要があるがこの書き方を選ぶ。 | ||
|
||
- 時間計算量: O(max(n,m)) |
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.
mはどこから来ましたか?
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.
コピペミスです><
線形リストを一度走査するだけなので、
- 時間計算量: O(n)
- 空間計算量: O(1)
|
||
# Step 3 | ||
|
||
この再帰の書き方が綺麗に思った。再帰のオーバーヘッドや呼び出し回数上限に気を配る必要があるがこの書き方を選ぶ。 |
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.
なぜ綺麗と思いましたか?綺麗と読みやすいはイコールですか?
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.
ちょっと言語化するために考えてみました。
なぜ綺麗と思いましたか?
レビュー依頼時点で綺麗と思った理由は、「注目するものの数が少ないと感じた」からです。ヘルパー関数の2つの引数という形で(仕事の引き継ぎという比喩における)引き継がれるものが明確に渡されており、そこに注目して処理するだけで済む感覚を持ったからです。
ただ、今考えると、「注目するものの数が少ない」というのは勘違いかもしれないと気づきました
多分whileループで処理する時と、注目している要素の数は同じはず。。僕のwhileループ側の理解が甘いからそう感じたのかもと思いました
綺麗と読みやすいはイコールですか?
大前提、Step 3の選定において、他者が読みやすいという観点を持てていなかったので、反省します。
その上で、いまも「ヘルパー関数の方が読みやすい」はずだとも思っています。一方気になる点も残っていて
- 他の人はループで書いてる人が多かった
- そういえば、この問題に限らずループを選択している割合が多いような気がする。
- 読み出し回数上限や関数呼び出しのオーバーヘッドがあるから避けてるのかと思ってましたが、そもそもループの方が直感的なのかもしれないと気づきました。
- このアンケートの結果とも一致していますし。
|
||
```python | ||
class Solution: | ||
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: |
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.
node_in_originalとnode_in_reversedあたりが端的で良いかなと思います。命名は難しいですね。
if head is None: | ||
return None | ||
reversed_tail = self.reverseList(head.next) | ||
head.next = None |
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.
これ、実は結果的に head.next がある場合には reversed_tail の一番後ろのノードになっているので、None かどうかをチェックして、最後にぶらさげると全部調べる必要がないんですよね。ただ、それだとちょっとテクニカルで読みにくいですね。その場合は self.reverseList を呼ぶ前に head.next をあらかじめ変数に入れておいたら分かりやすいと思います。
```python | ||
class Solution: | ||
# returns head node and last node | ||
def _reverseListRecursive(self, head: Optional[ListNode]) -> Tuple[Optional[ListNode],Optional[ListNode]]: |
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.
, のあとにスペースを入れるとよいと思います。
Tuple[Optional[ListNode], Optional[ListNode]]:
if head.next is None: | ||
return head, head | ||
reversed_head, reversed_last = self._reverseListRecursive(head.next) | ||
reversed_last.next = 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.
next に None を代入したあと、 next に一つ前のノードを代入しなおしているあたりが複雑に感じました。 step2 の実装のほうがシンプルに感じられました。
```python | ||
class Solution: | ||
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
def reverseListHelper(current_head: Optional[ListNode], reversed_head: Optional[ListNode]) -> Optional[ListNode]: |
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.
元のリンクリストにおいては、 reversed_head が一つ前、 current_head が現在注目しているノードとなっているため、引数も reversed_head, current_head の順にしたほうが直感的だと感じました。
また head はリンクリストの先頭のノードを表す言葉であり、関数の呼び出しごとに異なるノードを表している点に違和感を感じました。
|
||
# Step 1 | ||
|
||
線形リストを順に辿るやり方と、再帰を使うやり方を思いついた。 |
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.
空間計算量はO(N)になってしますが、時間計算量O(N)で一度スタックに入れてから順に取り出していく方法もあるかなと思いました。(個人的には一番最初に思いついた解法でした。)
意図的にスキップしていたらすみません。
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
stack = []
cur = head
while cur:
stack.append(cur)
cur = cur.next
reversed_head = ListNode(None)
reversed_cur = reversed_head
while stack:
node = stack.pop()
reversed_cur.next = ListNode(node.val)
reversed_cur = reversed_cur.next
return reversed_head.next
https://leetcode.com/problems/reverse-linked-list/description/