Skip to content

142. Linked List Cycle II.md #5

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions 142. Linked List Cycle II.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@

URL: https://leetcode.com/problems/linked-list-cycle-ii/description/

# Step 1

- 実装時間: 5分
- 時間計算量: O(n)
- 空間計算量: O(n)
- フロイドのアルゴリズムでも解けると聞いた気がしたけど、理解してないので変数に記録する解放で解く。

```python
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
node = head
nodes = set()
while node is not None:
if node in nodes:
return node
nodes.add(node)
node = node.next
return None
```

# Step 2

- `nodes`という変数名がいまいち。
- すでに訪問済みであることを意味する`visited`にしよう。
- Javaのクラスやフィールド名には一般的に名詞(句)なので、`visited_nodes`になる。
- https://github.com/canisterism/leetcode/pull/3/files#r1688327425

- フロイドの循環検出の理解

- https://github.com/ichika0615/arai60/pull/2/files#r1807227628
- `かめがスタート地点に戻った時、うさぎはどこにいるでしょうか。実は、うさぎは衝突点にいます。なぜかというと、うさぎは倍速で走っているからです。スタート地点から衝突点を通って衝突点に到達するうさぎルートの長さは、スタートから衝突点に到達するかめルートの2倍だからです。`
- ここちょっと混乱したので咀嚼してみる。
- `スタート〜合流点`の距離はn(亀の歩いた距離だから)
- `スタート〜合流点`の距離は2n(うさぎの歩いた距離だから)
- ということは、「うさぎのいる位置(2n)」から、うさぎがn歩戻ると「スタートからの距離が2n-nの場所」にいる。つまり「亀の歩いた距離n」と等しく、すなわちそこは合流点。
- setで解けることが常識の範囲
- https://github.com/codgas/leetcode/pull/2/files#r1717036142

なにはともあれ、フロイドの循環検出も実装してみる。

- ヘルパー関数を使った方がわかりやすい気がした。
Copy link

Choose a reason for hiding this comment

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

構造の前後を入れ替えたいときに、
https://discord.com/channels/1084280443945353267/1221030192609493053/1225674901445283860

  • 関数化。
  • Python 独特の文法。
  • 無限ループを使う。

などの方法があります。


```python
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
def find_meeting_point(head: Optional[ListNode]) -> Optional[ListNode]:
fast = head
slow = head
meeting_node = None
Copy link

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:
fast = fast.next.next
slow = slow.next
if slow == fast:
return slow
return None
Comment on lines +53 to +58
Copy link

Choose a reason for hiding this comment

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

whileの条件分岐はfastを使っていてnodeの更新もfastからするなら、ifの条件の左辺をfastにしてreturnで返す値もfastにしないのかな~と思いました。
処理は全く変わらないですが、なんとなく気になったところです。

Copy link
Owner Author

@katataku katataku Nov 17, 2024

Choose a reason for hiding this comment

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

ありがとうございます。言われるまで全く気づきませんでした。。。

以下、自分の調べたメモ:


fast = find_meeting_point(head)

Choose a reason for hiding this comment

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

ここでの変数名がfastなのはちょっと気になります。まあ好みの範囲かもしれないですが、うさぎが亀に追いついた後は、どちらも1つずつしか進まないのでslow, fastという命名はちょっと違うなという気持ちがあります。

Copy link
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます。たしかに・・・

他の方の書き方を見てみたので、まとめ:

  • node1, node2とやっているパターン
  • from_headという書き方のパターン。
    • 142. Linked List Cycle II colorbox/leetcode#18
    • from_headと合わせるなら、from_meeting_pointにするとbetterかと思った。とはいえ、slowが一歩づつというのは変わっていない情報なので、あまりこだわらなくていいかも。

if fast is None:
return None
slow = head
while fast != slow:
fast = fast.next
slow = slow.next
return fast
```


# Step 3

- 時間計算量: O(n)
- 空間計算量: O(n)

```python
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
node = head
visited = set()
while node is not None:
if node in visited:
return node
visited.add(node)
node = node.next
return None
```