From 2c389ac4de3ee6cadcd123d25b44eb7c19c0ab99 Mon Sep 17 00:00:00 2001 From: TrsmYsk <53941356+TrsmYsk@users.noreply.github.com> Date: Fri, 26 Sep 2025 22:14:24 +0900 Subject: [PATCH] Create 142. Linked List Cycle II.md --- .../142. Linked List Cycle II.md | 134 ++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 142. Linked List Cycle II/142. Linked List Cycle II.md diff --git a/142. Linked List Cycle II/142. Linked List Cycle II.md b/142. Linked List Cycle II/142. Linked List Cycle II.md new file mode 100644 index 0000000..7cd77cb --- /dev/null +++ b/142. Linked List Cycle II/142. Linked List Cycle II.md @@ -0,0 +1,134 @@ +問題文: https://leetcode.com/problems/linked-list-cycle-ii/ + +# step1: 何も見ないで書く +## setを使った方法 +- 時間計算量: O(n), 空間計算量 O(n)。 +- 前回もらったコメントを参考に条件を整えた。 +- ループ条件は ```while node:```でもいいが、個人的に読みにくい気がしたので```is not```で判定した。 +```python +class Solution: + def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: + visited = set() + node = head + while node is not None: + if node in visited: + return node + visited.add(node) + node = node.next + return None + +``` + +## フロイドの方法 +- 時間計算量: O(n), 空間計算量 O(1)。 +- 自力では思いつかなかったので、新井さんの解説を見た。 +- ループがネストされて読みにくいが、読みやすくする方法をすぐには思いつかなかったのでとりあえずこれで提出。 +```python +class Solution: + def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: + if head is None: + return None + fast = head + slow = head + while fast.next is not None and fast.next.next is not None: + fast = fast.next.next + slow = slow.next + if fast is slow: + slow = head + while fast is not slow: + fast = fast.next + slow = slow.next + return slow + return None + +``` + +# step2: 他の人のレビューを見てコードを整える +## setを使った方法 +- 他の人は```set```オブジェクトの中身まで気にしていたが、自分は見落としていたのでドキュメントを調べた。 + - set型はハッシュ値を持つオブジェクトを格納するためのオブジェクトで、メンバーの判定```x in set```はハッシュ値を使ってオブジェクトの同一性をチェックしている。\ + https://docs.python.org/ja/3/library/stdtypes.html#set-types-set-frozenset + - したがって、```node in visited```でメンバーと判定された```node```を返せば、サイクルの始点と同一のオブジェクトが返されることが保証されている。 +```python +class Solution: + def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: + visited = set() + node = head + while node is not None: + if node in visited: + return node + visited.add(node) + node = node.next + return None + +``` + +## フロイドの方法 +- サイクルの検知とサイクルの始点の検出を分けると良いというコメントを参考に整えた。 + - 最初はフラグ変数で実装していたが、小田さんのコメントで構造化が不十分と指摘されていた。そのため、典型コメント集の「コードの整え方」を参考に```while else```構文で実装した。 + - ループのネストをやめたので始点検出のための2つめのループで新しい変数名を使いたくなる気持ちになりやすくなった気がする。 +- step1のコードの読みにくさはループのネストだけでなく変数名の流用も影響していたと気が付いた。 +- 2つめのループでウサギ役の変数にどのような名前を付けるか迷ったが、無難にfrom_meetingとした。from_collisionにしようかとも思ったがネットワークの文脈で出てくる専門用語と名前がかぶって紛らわしいのでやめた。 +```python +class Solution: + def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: + if head is None: + return None + fast = head + slow = head + while fast.next is not None and fast.next.next is not None: + fast = fast.next.next + slow = slow.next + if fast is slow: + break + else: + return None + from_start = head + from_meeting = fast + while from_start is not from_meeting: + from_start = from_start.next + from_meeting = from_meeting.next + return from_start + +``` + +# step3: 10分以内にミスなく3回書く +## setを使った方法 +```python +class Solution: + def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: + visited = set() + node = head + while node is not None: + if node in visited: + return node + visited.add(node) + node = node.next + return None + +``` + +## フロイドの方法 +```python +class Solution: + def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: + if head is None: + return None + fast = head + slow = head + while fast.next is not None and fast.next.next is not None: + fast = fast.next.next + slow = slow.next + if fast is slow: + break + else: + return None + from_start = head + from_meeting = fast + while from_start is not from_meeting: + from_start = from_start.next + from_meeting = from_meeting.next + return from_start + +``` +