Skip to content

Create 142LinkedListCicleII.md #3

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
88 changes: 88 additions & 0 deletions 142LinkedListCicleII.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
Linked list cycle II



# 142. Linked list cycle II

## すでに解いた方々(in:レビュー依頼 titleで検索)
- https://github.com/atomina1/Arai60_review/pull/1/files
- https://github.com/pineappleYogurt/leetCode/pull/3/files
- https://github.com/t0hsumi/leetcode/pull/2/files
- https://github.com/katataku/leetcode/pull/5/files
- https://github.com/ichika0615/arai60/pull/2/files

## Step 1
- ループが閉じる番号を探すなら順序を考慮するリストの方が良いのかなと思い、最初はリストで解いてみようとするも、計算時間オーバーでギブアップ
Copy link

Choose a reason for hiding this comment

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

in の判定が、中身を頭から全部舐めて確認しているので、数がたくさんに増えるにつれて遅くなっていくんですね。

Copy link
Owner Author

Choose a reason for hiding this comment

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

なるほど。「なんとなくこの辺のせいなのかな」くらいの感度しかなかったので、もう一度見返してみます。

- https://github.com/pineappleYogurt/leetCode/pull/3/files を拝見して、先の問題と同じようにsetで解いてnodeをreturnすれば良さそうと理解して書き直す
- すでに解いた方々の回答と付き合わせてもそんなに悪くなさそう…?今の実力だとどんなコメントがつくか予想がつかない。
Copy link

Choose a reason for hiding this comment

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

ここまでついたような細かい表現方法を整える方法の趣味趣向以外は問題ないでしょう。


```Python
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
visited_node = set()
node = head

while node and node.next is not None:
Copy link

Choose a reason for hiding this comment

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

ここの部分はwhile nodeだけでも正しく動くと思います。while node and node.next is not None:としても、ループが一回回る回数が減るだけなので、自分ならwhile nodeにするかなと思います。

Copy link
Owner Author

Choose a reason for hiding this comment

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

深く考えずに過去のPRを反映していたのに気づけました。ご指摘ありがとうございます。

if node in visited_node:
return node
else:
visited_node.add(node)
node = node.next
Comment on lines +28 to +30
Copy link

@frinfo702 frinfo702 Dec 26, 2024

Choose a reason for hiding this comment

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

elseで書かなくてもいいのではないでしょうか?

Copy link
Owner Author

Choose a reason for hiding this comment

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

実際step2を経てそちらの方がなんとなく自然だなと感じるようになりましたが、やはりそちらの方が一般的な感覚なんだなと確信が持てました。ご指摘ありがとうございます。


return None
```

## Step 2
### Step2.1
- なぜ機能するのかさっぱりわからなかったフロイドのアルゴリズムについて小田さんが解説されていた:https://discord.com/channels/1084280443945353267/1246383603122966570/1252209488815984710
- 自分では絶対に思いつかないが、お絵描きしてみると言っていることは理解できた。時間が余った時にパズル的に聞かれることはあるとのことなので、おまけ気分で試しに書いてみる
- 先人のコードとレビューを見ていると、フロイドのアルゴリズムを使った場合はどうも前の問題でも言及されていたwhileの見通しが問題が生じやすそう:https://discord.com/channels/1084280443945353267/1221030192609493053/1225674901445283860 Python独自の書き方というのがよく分かっていないので、1度試しに書いてみる(Whileとelseを並列させている部分がPython独自なのかな?)
- が、たいしてif文の中が長くないので他の書き方でもよかった気がする。whileを2つ並べているのがまとめられそうでなんとなく気に食わない。

Choose a reason for hiding this comment

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

確かにfast_nodeとslow_nodeがぶつかった場合に片方のポインタを最初の位置に戻してまた一つずつ動かせということなので、二つあるwhile文を一つにまとめることはできると思います。while文の中が長くなっちゃうので読めるようにする工夫はいるかもしれません。

- 先人の主語云々というのが取り入れられなかった気がするが、fast slowの順番の話なので、今回自分が書いたものとは関係ない…? https://github.com/katataku/leetcode/pull/5/files#r1845483049

```Python
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
fast_node = head

Choose a reason for hiding this comment

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

この関数内で扱われる対象がNodeであることは明らかであるため、わざわざnodeまで書かなくてもいいのではと思いましたがいかがでしょう?
katataku/leetcode#2 (comment)

Copy link
Owner Author

Choose a reason for hiding this comment

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

なるほど、ありがとうございます

slow_node = head

# detect a collision point
while fast_node and fast_node.next is not None:
fast_node = fast_node.next.next
slow_node = slow_node.next
if fast_node is slow_node:
break
else:
return None

node_from_start = head

Choose a reason for hiding this comment

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

上同様ここもnodeであることは明らかで、使用する範囲も数行なのでstartなどでもいいかなと思いました(startだとちょっと汎用的すぎるかもですが)

node_from_collision = fast_node

# detect a intersection
while node_from_start is not node_from_collision:
node_from_start = node_from_start.next
node_from_collision = node_from_collision.next
else:
return node_from_start
```

## Step 3
とりあえずフロイドの方法のやり方自体は理解したが、実際に書くときはSetで書きたいなと思ったのでそちらで書いてみる。
時間を測りながら書いてみたらStep1のようにwhile->if->elseを使うのではなく、while->ifみたいな構造になっていた。
こっちの方がシンプルそうだなと感じてこちらを採用
1回目:4:59, 2回目:2:20, 3回目:2:20
```Python
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
node = head
visited_node = set()
Copy link

Choose a reason for hiding this comment

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

自分ならvisitedもしくはvisited_nodesとするかなと思います。


while node and node.next is not None:
Copy link

Choose a reason for hiding this comment

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

Noneとの比較に、is notを使うものと使わないものが混在しているのが気になりました。

また、ここの部分でもwhile nodeだけでも正しく動くと思います。

visited_node.add(node)
node = node.next
if node in visited_node:
return node

return None

```