Skip to content

141. Linked List Cycle - #1

Open
kazizi55 wants to merge 4 commits into
mainfrom
141-linked-list-cycle
Open

141. Linked List Cycle#1
kazizi55 wants to merge 4 commits into
mainfrom
141-linked-list-cycle

Conversation

@kazizi55

@kazizi55 kazizi55 commented Aug 6, 2025

Copy link
Copy Markdown
Owner

@kazizi55
kazizi55 marked this pull request as ready for review August 6, 2025 22:54
@kazizi55 kazizi55 self-assigned this Aug 6, 2025
@Apo-Matchbox

Copy link
Copy Markdown

pythonにあまり明るくないので、他の範囲でコメント致します。
current_nodeを、このくらいの問題ではnodeと表記へ変更している点など全体的に読みやすく改善されていると思いました。

visited_nodes = set()
current_node = head

while current_node != None:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Noneとの比較はis や is notを使うのが良さそうです。

Comparisons to singletons like None should always be done with is or is not, never the equality operators.
https://peps.python.org/pep-0008/#programming-recommendations

これからLeetCodeを解いていく中でデザインに関して疑問に感じた箇所はpep8を参照するのがいいと思います。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます!!
確かに None などの singleton との比較で is か is not を使わないのは直感的でないですね。

step 4として修正してみました!
Add step4

slow = slow.next
fast = fast.next.next

if (slow == fast):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

条件ぶんに括弧をつけるのかつけないのかは統一したほうがいいと思いました。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます!!
ちなみに pep8 には記載がなかったので、一旦括弧なしで統一してみることにします。(任意のものをあえて毎回書くのは冗長だなと思った次第です)

step4として修正してみました!
Add step4

@skypenguins

Copy link
Copy Markdown

だいたい皆さんと同じ感想が浮かびましたが、概ね読みやすかったです。

初回トライでは、走査した ListNode を dict に格納して ({ListNode: Bool} の形を想定)、 head.Next() を loop で回しながら dict と照合させるのがいいと思って進めていたが、そもそも Python でどうやって dict を作るのかや loop を回したらいいかがパッと出てこなく、調べていたら 5 分経ってしまっていた。本協会に入るまで Python に触ったことはほぼなく、入会後に LearnPython を数日でサッとこなした程度の習熟度だったのが要因と考えている。

2 回目のトライで 5 分以内に正解にできた。LeetCode の[こちらの回答](https://leetcode.com/problems/linked-list-cycle/solutions/3999014/99-68-two-pointer-hash-table/)を参考にした。Code Two-Pointer と Code Hash Table の 2 パターンがあったが、Code Two-Pointer は時間計算量こそ小さいが直感的でないと感じた (Floyd's Tortoise and Hare Algorithm に則ったものらしい。([記事](https://medium.com/@anudeepballa7/floyds-tortoise-and-hare-algorithm-6d439cdefde5)) ) ので、Code Hash Table の方を選択した。今回の目的は既出の ListNode と照らし合わせることが目的だったので元々考えていた dict は冗長だったことに気づけた。
また、解答例はなぜ list() ではなく set()なのかと思ったが、前者は ordered、後者は unordered な collection で前者の方がオーバーヘッドがあるためと理解した。現に、LeetCode で list()に書き換えて提出してみたら、時間計算量に大きな違いがあり、興味深かった。(set()が Runtime: 36ms に対して、list()が Runtime: 843ms)

Copy link
Copy Markdown

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/1196498607977799853/1270740093220687903

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

ご指摘ありがとうございます!
はい、おっしゃる通り、混同していました 🙏
今回のmemoの内容だと、「時間計算量に大きな違いがあり」 -> 、「実行時間に大きな違いがあり」 とすべきでしたね。

時間計算量的には、以下が言えるということですね

  • list() でも set() でもO(n)になる
  • 今回の hare and tortoise algorithm と set() を使った解答はともにO(n)と言える (前者は速いポインタが遅いポインタに追いつくまでにリスト全体を走査する可能性があり、後者も同様に一致する node を見つけるまでにリスト全体を走査する可能性がある)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

list() でも set() でもO(n)になる

要素の検索にかかる時間計算量についてであれば、 list は先頭から一つずつ要素を探すため O(n) になります。一方、 set() は CPython であればハッシュテーブルが使われるため、 O(1) になります。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

setのunorderedのところでもう少し、hasableだから探索が短いstepで済むみたいな言及が欲しいかもしれないです。また、平均計算量ではなくて、最悪計算量で思考されてる印象を受けました。

Runtimeは手元で計測する方が良いかもしれません。
brood0783/arai60#2 (comment)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます!

setのunorderedのところでもう少し、hasableだから探索が短いstepで済むみたいな言及が欲しいかもしれないです

なるほど、盲点でした。cpythonでもhash化して探索している様子が確認できますね。(9個の連続したエントリをチェックし、そのあとはランダムにチェック)
https://github.com/python/cpython/blob/481d5b54556e97fed4cf1f48a2ccbc7b4f7aaa42/Objects/setobject.c#L79-L121

また、平均計算量ではなくて、最悪計算量で思考されてる印象を受けました。

こちらも意識していなかったです。
平均計算量で見ると、listもsetも要素の追加はO(1)になり、検索だとlistがO(n)、setがO(1)になりますね。
一方で最悪検索量で見てみても、要素の追加はlistでもsetでもO(n)になり(配列のリサイズ・コピーが必要になる場合。ただしsetは稀)、検索だとlistもsetもO(n)になりますね (setはハッシュ値の衝突が発生した場合。こちらも稀)。

今後は基本は平均計算量で思考するようにし、最悪計算量も必要に応じて考えるようにします。

Runtimeは手元で計測する方が良いかもしれません。

確かにleetcode上だとだいぶブレますもんね。
手元でテストデータを100個作って計測してみました!

list():
Screenshot 2025-08-12 at 9 51 11

set():
Screenshot 2025-08-12 at 9 51 46

hare and tortoise:
Screenshot 2025-08-12 at 9 52 16

やはり 実行時間は list() > set() > hare and tortoise になるようでした

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

listもsetも時間計算量がO(n)というところが気になってコメントしたかったのですが、ご自身で解決されたようで良かったです。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

最初の取り組みとしてすごくやる気を感じました。

Comment on lines +55 to +57
### Step 3

set()を使う方法で実装。3 回実装してみて大きく内容は変わらなかったが、3 回目で問題文に出てくる語彙を使う方が読み手側にとってより直感的かなと思い、visited_nodes から reached_nodes という名前に変えてみた。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

visitedで良い気がします。reachだと到達なので、そこで終わるニュアンスが強い気がします(「範囲」という意味で使っている場合は、走査の範囲のニュアンスがあり、これもカタカナ語に近い違和感があります。そもそも一意に意味が確定しずらい)。visited_flagとかの方が聞いたことが多いので、あくまで一つの提案です。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます!
確かにcambridge dictionaryを見てみても、reach の意味としてはto arrive at a place, especially after spending a long time or a lot of effort travelingなので、やはり到達と言う意味で捉える方が良さそうですね。
https://dictionary.cambridge.org/us/dictionary/english/reach

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

問題を解いた反省としてのMEMOと、次に繋げる改善としてのMEMOが両方MEMOになってるので、分けて書くか、何らかの工夫をするともっと読みやすくなると思います。
現状「step4から改善なんだな〜」と、空気を読めばわかるのですが...

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

全体的にコードが読みやすいです。参照リンクも追いやすいです。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

現状「step4から改善なんだな〜」と、空気を読めばわかるのですが...

ありがとうございます!
Step 4の説明のところに「レビューをもとに改善」と記載しているのですが、わかりづらかったですね。
https://github.com/kazizi55/coding-challenges/pull/1/files#diff-0ac89d0fb94529b2b9ec468c4157cfdfc6e0406d959283f2e8307878c7a1a213R12-R13

フィードバックであることを明示してみました!今後もその方針でやってみます
9d1c628

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants