-
Notifications
You must be signed in to change notification settings - Fork 0
Solve 142. Linked List Cycle II (step 1, 2) #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?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| # step1 | ||
|
|
||
| set を使用した space complexity O(N)の方法はすぐに思いつく. | ||
| 問題は O(1)の場合. Floyd のアルゴリズムで, 合流までの回数などを用いて計算すれば求まりそうだが, あまり自明ではないだろう. Brent のアルゴリズムを使えば求められるだろうが, これも常識の範囲には入らず, 読むには負荷がかかるのではないだろうか. | ||
| ということで今回は set を使用したアルゴリズムで書く. | ||
|
|
||
| やはり Floyd の方法でも解く. | ||
| アルゴリズムは editorial にある通り. ループは 2\*a+b 回ほどまわる. | ||
| メソッドの命名が統一されていないが, leetcode の都合上 detectCycle は変更できないのでしかたがない. | ||
|
|
||
| # step2 | ||
|
|
||
| 見た回答 | ||
|
|
||
| - Google docs の sample answer | ||
| - https://discord.com/channels/1084280443945353267/1195700948786491403/1196010117120925777 | ||
| - キャンベルの法則を知る | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. グッドハートの法則とかも近いですね。こういった法則は博物学的な感じで統一的に何かを説明するものではないですが、名前を知っていることで存在を意識できるようになりますね(ジョシュアツリーの法則)
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. なるほど, ”名前を知ると意識できるようになる”という法則にも名前がついているのですね. |
||
| - https://discord.com/channels/1084280443945353267/1200089668901937312/1205725280556023898 | ||
| - "エッジケースを先にケアしておくことで読む人がエッジケースの考慮ができてるかを確認する手間が減るメリットもある"というのは参考になる. | ||
| - メソッドの中で関数を定義するのと, クラスに内部用のメソッドを追加するのだとどういうメリット・デメリットがあるだろうか. 他にも catchup point を知りたいメソッドがある場合は, メソッドを追加する方法が良いだろう. 一方で"\_"から始まるメソッドは完璧には private ではないというデメリットもある. | ||
| - from_start, from_catchup という命名は良いと思った. また, 自分のコードの collision という命名は少々わかりにくい. | ||
|
|
||
| 以上を参考に書く. | ||
| set を用いた方法はそんなに変わらず. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| # Definition for singly-linked list. | ||
| # class ListNode: | ||
| # def __init__(self, x): | ||
| # self.val = x | ||
| # self.next = None | ||
|
|
||
| class Solution: | ||
| def _get_collision_node(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| fast_cursor = head | ||
| slow_cursor = head | ||
| while fast_cursor and fast_cursor.next: | ||
| fast_cursor = fast_cursor.next.next | ||
| slow_cursor = slow_cursor.next | ||
| if fast_cursor == slow_cursor: | ||
| return fast_cursor | ||
| return None | ||
|
|
||
| def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| collision_node = self._get_collision_node(head) | ||
| if not collision_node: | ||
| return None | ||
| head_cursor = head | ||
| collision_cursor = collision_node | ||
| while head_cursor != collision_cursor: | ||
| head_cursor = head_cursor.next | ||
| collision_cursor = collision_cursor.next | ||
| return head_cursor |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| # Definition for singly-linked list. | ||
| # class ListNode: | ||
| # def __init__(self, x): | ||
| # self.val = x | ||
| # self.next = None | ||
|
|
||
| class Solution: | ||
| def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| seen_nodes = set() | ||
| while head: | ||
| if head in seen_nodes: | ||
| return head | ||
| seen_nodes.add(head) | ||
| head = head.next | ||
| return None |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| # Definition for singly-linked list. | ||
| # class ListNode: | ||
| # def __init__(self, x): | ||
| # self.val = x | ||
| # self.next = None | ||
|
|
||
| class Solution: | ||
| def _get_catchup_node(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| fast_cursor = head | ||
| slow_cursor = head | ||
| while fast_cursor and fast_cursor.next: | ||
| fast_cursor = fast_cursor.next.next | ||
| slow_cursor = slow_cursor.next | ||
| if fast_cursor == slow_cursor: | ||
| return fast_cursor | ||
| return None | ||
|
|
||
| def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| catchup_node = self._get_catchup_node(head) | ||
| if not catchup_node: | ||
| return None | ||
| from_head = head | ||
| from_catchup = catchup_node | ||
| while from_head != from_catchup: | ||
| from_head = from_head.next | ||
| from_catchup = from_catchup.next | ||
| return from_head |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| # Definition for singly-linked list. | ||
| # class ListNode: | ||
| # def __init__(self, x): | ||
| # self.val = x | ||
| # self.next = None | ||
|
|
||
| class Solution: | ||
| def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| seen_nodes = set() | ||
| while head: | ||
| if head in seen_nodes: | ||
| return head | ||
| seen_nodes.add(head) | ||
| head = head.next | ||
| return None |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| # Definition for singly-linked list. | ||
| # class ListNode: | ||
| # def __init__(self, x): | ||
| # self.val = x | ||
| # self.next = None | ||
|
|
||
| class Solution: | ||
| def _search_catchup_node(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| fast_cursor = head | ||
| slow_cursor = head | ||
| while fast_cursor and fast_cursor.next: | ||
| fast_cursor = fast_cursor.next.next | ||
| slow_cursor = slow_cursor.next | ||
| if fast_cursor == slow_cursor: | ||
| return fast_cursor | ||
| return None | ||
|
|
||
| def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| catchup_node = self._search_catchup_node(head) | ||
| if not catchup_node: | ||
| return None | ||
| from_start = head | ||
| from_catchup = catchup_node | ||
| while from_start != from_catchup: | ||
| from_start = from_start.next | ||
| from_catchup = from_catchup.next | ||
| return from_start |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # Definition for singly-linked list. | ||
| # class ListNode: | ||
| # def __init__(self, x): | ||
| # self.val = x | ||
| # self.next = None | ||
|
|
||
| class Solution: | ||
| def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| seen_nodes = set() | ||
| cursor = head | ||
| while cursor: | ||
| if cursor in seen_nodes: | ||
| return cursor | ||
| seen_nodes.add(cursor) | ||
| cursor = cursor.next | ||
| return 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.
Brent’s Cycle Detection Algorithmは自分は知らなかったです。
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.
ありがとうございます!141. Linked List Cycleを解いていたときにこのwikiを見てたまたま知っていたのですが, 勝手にループの開始地点が分かると勘違いしていました. 実装参考になります, Floydのときと同じような形で開始点も見つけられそうなのですね.