Skip to content

Solved 142_Linked_List_Cycle_2#2

Open
rieuky wants to merge 3 commits into
mainfrom
142_linked_list_cycle_2
Open

Solved 142_Linked_List_Cycle_2#2
rieuky wants to merge 3 commits into
mainfrom
142_linked_list_cycle_2

Conversation

@rieuky

@rieuky rieuky commented Apr 30, 2025

Copy link
Copy Markdown
Owner

This problem
-> 142. Linked List Cycle II

Next
-> 83. Remove Duplicates from Sorted List

Language
-> Python3

Comment thread solution_142.md
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
slow = head
fast = head
while fast and fast.next:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ファイル上部に記載されたコメントを踏まえると while fast is not None and fast.next is not None: と書くこともありだと思います。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

厳密に(保守的に)書くと読みづらいかと思い、可読性を優先して簡潔に書きましたが、コード内で一貫性があったほうがよいのは確実ですね。

レビューありがとうございます。

Comment thread solution_142.md
fast = fast.next.next
if slow is fast:
fast = head
while fast is not slow:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

個人的にはネストが深いなと思いました。コードの整え方や他の人が書いたコードを見た上でしっくりくる形に落ち着いているのであれば良いと思います。
https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.9kpbwslvv3yv

@nktr-cp nktr-cp Apr 30, 2025

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

私もネストが深いのが少し気になりました.
slowとfastがぶつかる地点を求めるロジックを実装した関数を用意するのはどうでしょう?

以下,他の方の実装例です.
https://hayapenguin.com/notes/LeetCode/142/LinkedListCycleTwo

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

お二方、丁寧に参考資料までありがとうございます。

そこまで考えが及んでいなかったので、非常に勉強になりました。
今後は「構造的可読性」に配慮して、複数の選択肢の中から書き方を決めたいと思います。

特に、while ~ else は書いたことがなかったので、書いてみました。

class Solution:
    def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
        slow = head
        fast = head
        while fast and fast.next:
            slow = slow.next 
            fast = fast.next.next
            if slow is fast:
                break
        else:
            return None # -> no cycle found

        fast = head
        while fast is not slow:
            slow = slow.next
            fast = fast.next
        return fast

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

そうですね。必ずどれを使うべきというのはないのですが、頭の中でこういう変形をたくさんしてしっくりくるものを探しています。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

思考の流れをコードに落としこむだけでなく、その書き方・構造を初見の人が一読で理解できるかという観点が重要だと受け取りました。訓練で身につけたいと思います。

Comment thread solution_142.md
return current
visited.add(current)
current = current.next
return None

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

とても読みやすいと思います!
ネストを浅くする方法として,

# currentが末尾に達するか,
# visitedなノードに達するまでwhile
while current is not None and current not in visited:
    visited.add(current)
    current = current.next

return current

とすることが考えられますが,どちらが読みやすいかは人による気がしますね.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます!

どの深さのネストまで許容するか、チーム内でルールを決めておくと、バランスの取れた選択ができそうです。

Comment thread solution_142.md
fast = fast.next.next
if slow is fast:
fast = head
while fast is not slow:

@nktr-cp nktr-cp Apr 30, 2025

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

私もネストが深いのが少し気になりました.
slowとfastがぶつかる地点を求めるロジックを実装した関数を用意するのはどうでしょう?

以下,他の方の実装例です.
https://hayapenguin.com/notes/LeetCode/142/LinkedListCycleTwo

Comment thread solution_142.md
fast = head
while fast is not slow:
slow = slow.next
fast = fast.next

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

こちら,fast変数が再度使用されて,

fast = head

としたあと,今度は1つづつ進んでいる (fastに進んでいない) のが気になりました.
別の変数を用意してはどうでしょうか (上のリンクの方の実装だと,from_start).

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

ご指摘通り、

  • 連結リストのサイクル検知
  • サイクル開始点の探索

は(繋がっているが)別の処理なので、from_start などの別の参照だと意味的に分かる変数名にすべきだと思いました。ありがとうございます。

Comment thread solution_142.md
fast = fast.next.next
if slow is fast:
fast = head
while fast is not slow:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

そうですね。必ずどれを使うべきというのはないのですが、頭の中でこういう変形をたくさんしてしっくりくるものを探しています。

Comment thread solution_142.md
- 両辺 mod l_cycle を取ると、d (mod l_cycle) = (- l_in) (mod l_cycle)
- これより、合流地点から距離 l_in 進めば、サイクルの入口に達することが分かる。
- ただ、具体的な l_in は分からない(それを求めるのが題意なので)。
- だが偶然にも、l_in は head からサイクル入口までの距離なので、片方のポインタを head に戻せば、合流地点からスタートするポインタ A と head から移動するポインタ B を同じ速度で動かせば、ちょうどサイクル入口で合流することになる。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます。拝読しました。

ところで、この戻っていく時、うさぎとかめは、衝突点から同じ速さで歩いて戻っているので、合流点までは一緒にいましたね。

サイクル開始点を求めるテクニック(処理)は、数式を使わないと自分は納得できないと思っていましたが、この説明で腑に落ちました。

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.

4 participants