From 591968b30a6e2bb5d8180374758f71f7b2045830 Mon Sep 17 00:00:00 2001 From: mayota Date: Mon, 1 Jun 2026 22:59:49 +0900 Subject: [PATCH 1/6] step1 --- 141_Linked_List_Cycle/note.md | 18 ++++++++++++++++++ 141_Linked_List_Cycle/step1.py | 27 +++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 141_Linked_List_Cycle/note.md create mode 100644 141_Linked_List_Cycle/step1.py diff --git a/141_Linked_List_Cycle/note.md b/141_Linked_List_Cycle/note.md new file mode 100644 index 0000000..7523f59 --- /dev/null +++ b/141_Linked_List_Cycle/note.md @@ -0,0 +1,18 @@ +# 141. Linked List Cycle + +## step1(まず通す) + +イメージとしては「速いやつと遅いやつ2人が同じ道を同じ方向に進んで、速いやつが追いついたらループしてる、そうでないならループしてない」 + +fast は fast.next が None の場合に注意してないと None.next をやってエラーが出る + +ミス: + +- 進めるのと判定するのの順序を間違えて全部 head == head で True になる +- fast を一つしか進めない + +↑頭の中で挙動をシミュレートする力が弱っているので鍛え直す必要がある + +## step2(整形&他の人のコードを読む) + +## step3(10分以内にさっとかける * 3回) diff --git a/141_Linked_List_Cycle/step1.py b/141_Linked_List_Cycle/step1.py new file mode 100644 index 0000000..8b83194 --- /dev/null +++ b/141_Linked_List_Cycle/step1.py @@ -0,0 +1,27 @@ +from typing import Optional + + +# 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: + # リストを先頭から一つずつ歩いていくやつと1つ飛ばし(2倍速)で歩いていくやつがいて + # 速いやつが遅いやつに追いついたらループしてる + # どこかで None が出てきたらループしてない(そこが終端) + + slow = head + fast = head + + while slow is not None and fast is not None and fast.next is not None: + slow = slow.next + fast = fast.next.next + + if slow == fast: + return True + + return False From 40f00aef77ea5f619849ae8eb779a79b70abec0d Mon Sep 17 00:00:00 2001 From: mayota Date: Tue, 2 Jun 2026 00:34:20 +0900 Subject: [PATCH 2/6] step2 --- 141_Linked_List_Cycle/note.md | 38 +++++++++++++++++++++++++++--- 141_Linked_List_Cycle/step2.py | 27 +++++++++++++++++++++ 141_Linked_List_Cycle/step2_set.py | 23 ++++++++++++++++++ 3 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 141_Linked_List_Cycle/step2.py create mode 100644 141_Linked_List_Cycle/step2_set.py diff --git a/141_Linked_List_Cycle/note.md b/141_Linked_List_Cycle/note.md index 7523f59..d4fdc32 100644 --- a/141_Linked_List_Cycle/note.md +++ b/141_Linked_List_Cycle/note.md @@ -1,18 +1,50 @@ # 141. Linked List Cycle + + ## step1(まず通す) -イメージとしては「速いやつと遅いやつ2人が同じ道を同じ方向に進んで、速いやつが追いついたらループしてる、そうでないならループしてない」 +イメージとしては「速いやつと遅いやつ2人が同じ道を同じ方向に進んで、速いやつが追いついたらループしてる、そうでないならループしてない」(もともと知っていた) fast は fast.next が None の場合に注意してないと None.next をやってエラーが出る -ミス: +やったミス: - 進めるのと判定するのの順序を間違えて全部 head == head で True になる - fast を一つしか進めない -↑頭の中で挙動をシミュレートする力が弱っているので鍛え直す必要がある +↑頭の中で挙動をシミュレートする力が弱っているので鍛え直す必要がある。 ## step2(整形&他の人のコードを読む) +### 他のコード見る前 + +head , head.next, head.next.next が None の場合は早期リターンして +slow, fast を始めから1ステップ進めた状態で定義、ループの中では判定→進めるの順でやることも考えたけど、同じような条件式が2回出てくるのは見づらいだろうということで Step1のスタイルにした。 + +### 見たあと + +参考になったコード・コメント・ドキュメント + +- [他の方のメモ](https://github.com/naoto-iwase/leetcode/pull/1/changes/BASE..21cd6c5ca124e1b81b91b8003681e1a49b1c5927#diff-bb5a355bc7de70630b57c0d17d649e9adce45b5f0965089f22bf15dd4236d47fR75) + - [公式ドキュメント](https://docs.python.org/ja/3.13/library/stdtypes.html#comparisons) に「あるクラスの同一でないインスタンスは、通常等価でないとされますが、そのクラスが __eq__() メソッドを定義している場合は除きます。」「is および is not 演算子の振る舞いはカスタマイズできません。また、これらはいかなる 2 つのオブジェクトにも適用でき、決して例外を送出しません。」とあり、`==` は「(勝手に定義した)何らかの意味」で等しいというふうにできるのでオブジェクトが同一か知りたい今回は `is` を使うべき +- + - 気になるのは「fast は slow に追いついたか?」なので、fast is slow としたい +- + - 知ってたので Floyd の方法でやったが、「今見ているノードはすでに到達したか?」と考えて set でやる方が応用の効く(普通の)発想かもしれない + - set はハッシュマップだったはずなので `in` の判定も(衝突がなければ)O(1)だし、リストを線形に舐めるだけなのは変わらなそう + - [公式ドキュメント](https://docs.python.org/ja/3/library/stdtypes.html#set)にも「集合の要素は ハッシュ可能 なものでなくてはなりません」とあるし調べた感じそうらしいので間違いなさそう(本当は実装を読むべきなのでしょうが今日は時間がない) + - while の行に書く条件と while の中でループを抜けるために書く条件(少なくとも先頭か末尾なら)は、while を抜けるという意味で等価なのでどこに書くかのバリエーションが出る、という理解 + - 今回は、「終端に着くまで毎回『通った道じゃないよな?』と確認する」という気持ちだったので step2_set.py のように書いた + - + - Python では再起が好まれない話 + - デフォルトで深さが1000 + - 再帰的に定式化するとコードもそのまま書けるのでわかりやすい、という良さはあるがいつでも使えば良いってもんじゃない + - Python3 は末尾再帰最適化が効かないっぽい? +- [他の方のコード](https://github.com/shintaro1993/arai60/pull/3/changes#diff-491120a14a1981900662359b52a1c34fca42db491aff99fb79c9ba09193ba12fR109) + - fast が先に行ってくれており slow の next は None じゃないことが保証されているので `slow is not None` は書かなくても正しく動きはする + - ただしこれだと Mypy(型チェッカー) は赤線引いてくる(たぶん単純な型推論だとわからなくて、コードの内容くわしく見ないといけないから) + - どっちが好まれる? + - 一応チェックない方が O(n) の定数倍が削れるし単純に `and` で繋ぐ数が少なくて見やすい気がする + ## step3(10分以内にさっとかける * 3回) diff --git a/141_Linked_List_Cycle/step2.py b/141_Linked_List_Cycle/step2.py new file mode 100644 index 0000000..41f7ae1 --- /dev/null +++ b/141_Linked_List_Cycle/step2.py @@ -0,0 +1,27 @@ +from typing import Optional + + +# 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: + # リストを先頭から一つずつ歩いていくやつと1つ飛ばし(2倍速)で歩いていくやつがいて + # 速いやつが遅いやつに追いついたらループしてる + # どこかで None が出てきたらループしてない(そこが終端) + + slow = head + fast = head + + while fast is not None and fast.next is not None: + slow = slow.next + fast = fast.next.next + + if fast is slow: + return True + + return False diff --git a/141_Linked_List_Cycle/step2_set.py b/141_Linked_List_Cycle/step2_set.py new file mode 100644 index 0000000..9421e8e --- /dev/null +++ b/141_Linked_List_Cycle/step2_set.py @@ -0,0 +1,23 @@ +from typing import Optional + + +# 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: + current_node = head + visited_nodes = set() + + while current_node is not None: + visited_nodes.add(current_node) + current_node = current_node.next + + if current_node in visited_nodes: + return True + + return False From 85e0901ad8f85e8af07c0dd93fe9187115ec665a Mon Sep 17 00:00:00 2001 From: mayota Date: Tue, 2 Jun 2026 00:36:14 +0900 Subject: [PATCH 3/6] step3 --- 141_Linked_List_Cycle/note.md | 3 +++ 141_Linked_List_Cycle/step3.py | 23 +++++++++++++++++++++++ 141_Linked_List_Cycle/step3_set.py | 23 +++++++++++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 141_Linked_List_Cycle/step3.py create mode 100644 141_Linked_List_Cycle/step3_set.py diff --git a/141_Linked_List_Cycle/note.md b/141_Linked_List_Cycle/note.md index d4fdc32..552f4fe 100644 --- a/141_Linked_List_Cycle/note.md +++ b/141_Linked_List_Cycle/note.md @@ -48,3 +48,6 @@ slow, fast を始めから1ステップ進めた状態で定義、ループの - 一応チェックない方が O(n) の定数倍が削れるし単純に `and` で繋ぐ数が少なくて見やすい気がする ## step3(10分以内にさっとかける * 3回) + +個人的に書いてて「自然」に感じられるのは set 使う方、という感想。 +Floyd の方は「へーこんなやり方が」って感じな一方 set 使う方は「そりゃそうやろ」って感じで、おそらく後者の方がいい場面が多いので。 diff --git a/141_Linked_List_Cycle/step3.py b/141_Linked_List_Cycle/step3.py new file mode 100644 index 0000000..a07ae47 --- /dev/null +++ b/141_Linked_List_Cycle/step3.py @@ -0,0 +1,23 @@ +from typing import Optional + + +# 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: + slow = head + fast = head + + while fast is not None and fast.next is not None: + slow = slow.next + fast = fast.next.next + + if fast is slow: + return True + + return False diff --git a/141_Linked_List_Cycle/step3_set.py b/141_Linked_List_Cycle/step3_set.py new file mode 100644 index 0000000..9421e8e --- /dev/null +++ b/141_Linked_List_Cycle/step3_set.py @@ -0,0 +1,23 @@ +from typing import Optional + + +# 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: + current_node = head + visited_nodes = set() + + while current_node is not None: + visited_nodes.add(current_node) + current_node = current_node.next + + if current_node in visited_nodes: + return True + + return False From 994a864b58a10651ad1fa7cb4e0b301615ad332e Mon Sep 17 00:00:00 2001 From: mayota Date: Tue, 2 Jun 2026 00:36:57 +0900 Subject: [PATCH 4/6] rename files --- 141_Linked_List_Cycle/{step2.py => step2_floyd.py} | 0 141_Linked_List_Cycle/{step3.py => step3_floyd.py} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename 141_Linked_List_Cycle/{step2.py => step2_floyd.py} (100%) rename 141_Linked_List_Cycle/{step3.py => step3_floyd.py} (100%) diff --git a/141_Linked_List_Cycle/step2.py b/141_Linked_List_Cycle/step2_floyd.py similarity index 100% rename from 141_Linked_List_Cycle/step2.py rename to 141_Linked_List_Cycle/step2_floyd.py diff --git a/141_Linked_List_Cycle/step3.py b/141_Linked_List_Cycle/step3_floyd.py similarity index 100% rename from 141_Linked_List_Cycle/step3.py rename to 141_Linked_List_Cycle/step3_floyd.py From a8deb4f4725659bbfa331d40f754481d158f2b41 Mon Sep 17 00:00:00 2001 From: mayota Date: Tue, 2 Jun 2026 10:22:55 +0900 Subject: [PATCH 5/6] Update Note --- 141_Linked_List_Cycle/note.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/141_Linked_List_Cycle/note.md b/141_Linked_List_Cycle/note.md index 552f4fe..d405541 100644 --- a/141_Linked_List_Cycle/note.md +++ b/141_Linked_List_Cycle/note.md @@ -50,4 +50,4 @@ slow, fast を始めから1ステップ進めた状態で定義、ループの ## step3(10分以内にさっとかける * 3回) 個人的に書いてて「自然」に感じられるのは set 使う方、という感想。 -Floyd の方は「へーこんなやり方が」って感じな一方 set 使う方は「そりゃそうやろ」って感じで、おそらく後者の方がいい場面が多いので。 +Floyd の方は「へーこんなやり方が」って感じな一方 set 使う方は「まあそうだよな」って感じで、おそらく後者の方がいい場面が多いので。 From 2d5f0c6b71b3a4fbf015b93b5923409ae23e8da5 Mon Sep 17 00:00:00 2001 From: mayota Date: Mon, 22 Jun 2026 21:19:15 +0900 Subject: [PATCH 6/6] step4 --- 141_Linked_List_Cycle/step4.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 141_Linked_List_Cycle/step4.py diff --git a/141_Linked_List_Cycle/step4.py b/141_Linked_List_Cycle/step4.py new file mode 100644 index 0000000..287bf72 --- /dev/null +++ b/141_Linked_List_Cycle/step4.py @@ -0,0 +1,29 @@ +from typing import Optional + + +# 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: + # リストを先頭から一つずつ歩いていくやつと1つ飛ばし(2倍速)で歩いていくやつがいて + # 速いやつが遅いやつに追いついたらループしてる + # どこかで None が出てきたらループしてない(そこが終端) + + slow = head + fast = head + + while fast is not None and fast.next is not None: + assert slow is not None + + slow = slow.next + fast = fast.next.next + + if slow == fast: + return True + + return False