Skip to content

create 206 reversed linked list#9

Open
TrsmYsk wants to merge 1 commit intomainfrom
TrsmYsk-patch-5
Open

create 206 reversed linked list#9
TrsmYsk wants to merge 1 commit intomainfrom
TrsmYsk-patch-5

Conversation

@TrsmYsk
Copy link
Owner

@TrsmYsk TrsmYsk commented Oct 23, 2025

Document various approaches to solving the reverse linked list problem, including iterative and recursive methods, with detailed explanations and code examples.
Comment on lines +19 to +20
if head is None or head.next is None:
return head

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

この2行を省いても正しく動きますね。

番兵を使わない場合はif head is Noneの方は残すと思いますが、番兵を使われているのでこれも不要ということですね。

以降の実装についても同様です。

Comment on lines +6 to +8
- ループで実装するのが一番簡単な気がする。
- 再帰を使ったらスタック無しで実装できそうだけど、どんな手順になるかはすぐに思いつかない。
- 妥協案として、ノードをスタックしてから再帰的に逆順のリストを作る方法にした。

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

再帰は結局関数呼び出しのスタックであり、明示的なスタック + loop実装に対する糖衣構文なので、この順番で発想されるのは不思議な感じがします。

私が実装を考えるときは、再帰なら実装できる -> スタック + loopでも実装できないだろうか、という順番ですね。

fyiで、再帰関数のよる関数呼び出しのスタックは明示的なスタックと比べ、引数のコピー、呼び出し元の位置の記憶などが追加で必要なので一般的に重くなります。

また、デバッグがしづらかったり、pythonのデフォルトの再起上限は大抵1000程度(leetcodeは引き上げられているそうです)などの事情で、通常は再帰関数よりloop実装のが好まれます。

Copy link

@nodchip nodchip Oct 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

糖衣構文は、プログラミング言語において、複雑なイディオムを、簡単に書けるようにする機能のことを表すように思います。再帰はスタック + loop を簡単に書けるようにしているようには感じないため、糖衣構文というのは違和感があります。スタック + loop 実装は、再帰でも書ける、別実装である、等価である、相互変換変換できる、くらいに表現したほうが良いと思います。

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ありがとうございます。

ご指摘に異存ありません。用語のスコープに気をつけます、失礼しました...


## 直近のコード
https://github.com/docto-rin/leetcode/pull/7/files#r2403779253
- 入力されるリストを壊してもいいのかどうか。どう判断すべきか分からない。全ノードを逆転させることがわかっているから、入力を壊してもすぐに復元できそうな気がする。

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

以下、自分が以前いただいたレビューコメントで、参考になればと思います。

入力を変更している点が気になりました。呼び出し側の視点に立って考えると、関数に渡した値が勝手に書き換えられているとびっくりすると思います。入力は原則変更しないか、変更する場合は関数コメントでそれを明記することをおすすめします。

https://discordapp.com/channels/1084280443945353267/1421920158506549470/1426880686064795751

Comment on lines +182 to +186
reversed_tail = dummy
while reversed_nodes:
reversed_tail.next = reversed_nodes.pop()
reversed_tail = reversed_tail.next
return dummy.next

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reversed_nodesから逐次popしてるので逆順に進んでることは十分伝わるかなと感じました。

1回目のwhileループのように、reversed_tailは単にnodeの方が読みやすい気がします。

```python
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
def reverse_list_helper(disassembling_head: Optional[ListNode],reversed_head: Optional[ListNode]) -> Optional[ListNode]:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

この行は空白込みで128文字あるようです。PEP8では、

Limit all lines to a maximum of 79 characters.

となっているので、改行することをお勧めします。

https://peps.python.org/pep-0008/#maximum-line-length

また、innfer functionなどにtype hintを入れてもあまり読み手の助けにならないという意見を見たことがあります。

Comment on lines +146 to +160
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
def reverse_list_helper(node: Optional[ListNode]) -> Tuple[Optional[ListNode], Optional[ListNode]]:
if node is None:
return None, None
if node.next is None:
return node, node
reversed_head, reversed_tail = reverse_list_helper(node.next)
node.next = None
reversed_tail.next = node
reversed_tail = reversed_tail.next
return reversed_head, reversed_tail

reversed_head, reversed_tail = reverse_list_helper(head)
return reversed_head

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reversed_tailは再帰を呼び出した後でもnode.nextでアクセスできるので帰りがけの作業はreversed_tailなしでできます。reversed_headだけを返して書くこともできます。

class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if head is None or head.next is None:
            return head
        reversed_head = self.reverseList(head.next)
        head.next.next = head
        head.next = None
        return reversed_head

reversed_tail = reversed_tail.next
return reversed_head, reversed_tail

reversed_head, reversed_tail = reverse_list_helper(head)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reversed_tailは使わないので_で潰しておいてもいいかもしれません。趣味の範囲です。

Comment on lines +49 to +50
if head is None or head.next is None:
return head

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

自分は入力例外を弾く処理はinner functionの定義より上に書くようにしているのですが、趣味の範囲かもしれません。

inner functionは例外的な入力を弾いた前提で使う予定ですよ、というのを読み手に伝えたいからそうしています。

Comment on lines +129 to +140
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
def reverse_list_helper(disassembling_head: Optional[ListNode],reversed_head: Optional[ListNode]) -> Optional[ListNode]:
if disassembling_head is None:
return reversed_head
node = disassembling_head
disassembling_head = disassembling_head.next
node.next = reversed_head
reversed_head = node
return reverse_list_helper(disassembling_head, reversed_head)

return reverse_list_helper(head, None)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

末尾再帰の形なので、容易にiterativeに書き直せます。(他言語だとコンパイラが自動でやってくれます)

class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        disassembling_head = head
        reversed_head = None

        while disassembling_head is not None:
            node = disassembling_head
            disassembling_head = disassembling_head.next
            node.next = reversed_head
            reversed_head = node

        return reversed_head

空間計算量がO(1)で済み、時間計算量も定数倍で改善すると思います。

Comment on lines +6 to +8
- ループで実装するのが一番簡単な気がする。
- 再帰を使ったらスタック無しで実装できそうだけど、どんな手順になるかはすぐに思いつかない。
- 妥協案として、ノードをスタックしてから再帰的に逆順のリストを作る方法にした。
Copy link

@nodchip nodchip Oct 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

糖衣構文は、プログラミング言語において、複雑なイディオムを、簡単に書けるようにする機能のことを表すように思います。再帰はスタック + loop を簡単に書けるようにしているようには感じないため、糖衣構文というのは違和感があります。スタック + loop 実装は、再帰でも書ける、別実装である、等価である、相互変換変換できる、くらいに表現したほうが良いと思います。

- 時間計算量O(n), 空間計算量O(n)。
- ループで実装するのが一番簡単な気がする。
- 再帰を使ったらスタック無しで実装できそうだけど、どんな手順になるかはすぐに思いつかない。
- 妥協案として、ノードをスタックしてから再帰的に逆順のリストを作る方法にした。
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

カタカナ語でスタックという場合、名詞の意味か、動作が止まることを表す stuck の意味で使うように思います。スタックに積むと表現したほうが、スムーズに伝わるように思います。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants