-
Notifications
You must be signed in to change notification settings - Fork 0
Create 141. Linked List Cycle.md #37
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
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,102 @@ | ||
| フロイドの循環法の説明: | ||
| https://discord.com/channels/1084280443945353267/1246383603122966570/1252209488815984710 | ||
| ``` | ||
| はい。2歩ずつ走るうさぎと1歩ずつ歩くかめが、ある地点でぶつかったとします。そこを衝突点と呼びましょう。衝突点が見つかったあとに、衝突点とスタート地点から1歩ずつうさぎとかめを歩かせて、衝突するところが、合流地点である、ということを理解したいということですね。 | ||
|
|
||
| うさぎとかめは、衝突点で出会った後に、うさぎとかめは、いま来た道を戻るように言われました。うさぎもかめも同じ速さで1歩ずつ歩いて戻ります。このとき、うさぎは一周してから戻りますが、かめはそのまま戻ります。 | ||
|
|
||
| かめがスタート地点に戻った時、うさぎはどこにいるでしょうか。実は、うさぎは衝突点にいます。なぜかというと、うさぎは倍速で走っているからです。スタート地点から衝突点を通って衝突点に到達するうさぎルートの長さは、スタートから衝突点に到達するかめルートの2倍だからです。 | ||
|
|
||
| ところで、この戻っていく時、うさぎとかめは、衝突点から同じ速さで歩いて戻っているので、合流点までは一緒にいましたね。 | ||
|
|
||
| さて、ここまでの話を動画にして逆回しにしてみましょう。 | ||
|
|
||
| うさぎとかめは、それぞれ衝突点とスタート地点から同じ速さで後ろ向きに歩き始めます。そして、合流地点から一緒に後ろ向きに歩き始め、そして衝突点に到達します。 | ||
| ``` | ||
|
|
||
| * ObjectがHashableかどうかは常に考える。 | ||
| * ListNodeはHashable、Hashableでないものは、List, Dictなどのmutalbleなオブジェクト。 | ||
| * https://docs.python.org/ja/3/glossary.html#term-hashable | ||
| * ユーザ定義クラスはデフォルト場合hashableであり、ハッシュ値はid()に由来する。 | ||
| * ハッシュ可能なオブジェクトの比較には == 演算子で値を比較、オブジェクトの同一性チェックには is 演算子を使用 | ||
| * 選択肢として思いついたのは、setに使いしていく方法と、Floyd。 | ||
| * 再帰は選択肢になかったので頭に入れておく。 | ||
|
|
||
| ## setによる解法 | ||
|
|
||
| ### 1回目 (2m32s) | ||
| 時間計算量: O(N)<br> | ||
| 空間計算量: O(N)<br> | ||
|
|
||
| * 素直な問題なため真っ直ぐ解けた。 | ||
| * headがNoneだった場合を考慮して、if not headを書いても良いかもしれない。 | ||
| * ユーザーの目的によっては、assertしてエラーにしても良いかも。 | ||
|
|
||
| ```python | ||
| # Definition for singly-linked list. | ||
| # class ListNode: | ||
| # def __init__(self, x): | ||
| # self.val = x | ||
| # self.next = None | ||
|
|
||
| class Solution: | ||
| def hasCycle(self, head: Optional[ListNode]) -> bool: | ||
| seen = set() | ||
| while head: | ||
| if head in seen: | ||
| return True | ||
| seen.add(head) | ||
| head = head.next | ||
| return False | ||
| ``` | ||
|
|
||
|
|
||
| ## フロイドの循環検出法(Floyd's cycle-finding algorithm)による解法 | ||
| 時間計算量: O(N)<br> | ||
| 空間計算量: O(1)<br> | ||
|
|
||
| 計算量に関するmemo from goto-untrappedさん: | ||
| * 出会わなかったらO(n/2)=O(n)、 | ||
| * 出会う場合、サイクルに入るまで最大は、slowのO(n)、 | ||
| * 入ってから出会うまでが最大は、1ずつ縮まるのでO(n)、 | ||
| * なのでO(n)+O(n)=O(n) | ||
| https://github.com/goto-untrapped/Arai60/pull/21/commits/e0545f02716ea1c5824cc560a5602f8025532cf4 | ||
|
|
||
|
|
||
| ```python | ||
| class Solution: | ||
| def hasCycle(self, head: Optional[ListNode]) -> bool: | ||
| slow = head | ||
| fast = head | ||
|
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. 全体としてよくかけていると思いました. fast = slow = headも選択肢でしょうか?
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. ありがとうございます。 |
||
|
|
||
| while fast and fast.next: | ||
| slow = slow.next | ||
| fast = fast.next.next | ||
| if slow is fast: | ||
|
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. ListNode同士のオブジェクトの比較なので、isにしています。ここは同一のListNodeの比較想定なので、=でも問題ないですね。 |
||
| return True | ||
| return False | ||
| ``` | ||
|
|
||
| ## 再帰による解法 | ||
|
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. 様々な解法をご検討されており,よいと思います. class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
fast = slow = head
while 1:
if fast is None or fast.next is None:
return None
slow = slow.next
fast = fast.next.next
if slow == fast:
return Trueもいかがでしょうか 以下の議論も参考になります
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. ありがとうございます。無限ループの書き方もわかりやすいですね。参考になります。 |
||
| 時間計算量: O(N)<br> | ||
| 空間計算量: O(N)<br> | ||
|
|
||
| * もう少し良い関数名があるかも。 | ||
| * 復習として、クラスメソッドでない場合はselfは不要。 | ||
|
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. ありがとうございます。ご指摘の通りインスタンスメソッドですね。 |
||
|
|
||
|
|
||
| ```python | ||
| class Solution: | ||
| def hasCycle(self, head: Optional[ListNode]) -> bool: | ||
|
|
||
| def hasCycleHelper(node: Optional[ListNode], seen: Set[ListNode]) -> bool: | ||
| if not node: | ||
| return False | ||
| if node in seen: | ||
| return True | ||
| seen.add(node) | ||
| return hasCycleHelper(node.next, seen) | ||
|
|
||
| seen = set() | ||
| return hasCycleHelper(head, seen) | ||
| ``` | ||
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.
私の間違いだったら申し訳ないのですが,この下にseenにheadが含まれない場合はaddする必要がある気がします.
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.
私もadd必要だと思います。
ifの中でreturnしているので、ifの外であればelseはなくてもよさそうです。
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.
すみません、ご指摘頂きありがとうございます。
コピペの段階で誤って消したみたいです。クリティカルなのでここだけ部分的に修正しました。