Skip to content

142. Linked List Cycle #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 4 commits 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
73 changes: 73 additions & 0 deletions lc141.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""効率的な方法が特に思いつかなかったので愚直にやろうと思った。また、ListNodeの扱い方がよくわからなかったのでpythonのリストを用いた。一見良さそうなコードが書けたが、Nodeの中に同じ数字が入っているとダメであることに気づかずそこでsubmitも止まってしまった。(15分)"""

Choose a reason for hiding this comment

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

計算量の見積もり(時間、空間)もやっておくといいかもです。

Copy link

Choose a reason for hiding this comment

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

計算量の見積もりは、計算時間を見積もるためのものなので、本当は時間まで見積もっておいたほうがいいです。ただ、そんなに高い精度は必要ではありません。

class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
head_list = []
while head:
if head.val in head_list:

Choose a reason for hiding this comment

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

step2以降はset()になっているので問題ないですが、この問題ではlistを使うかsetを使うかで顕著にスピード差が出ます。
Leetcode上で何度か実行すると、listで600ms、setで45sぐらいだと思います。
この理由は把握していますか?

Copy link
Owner Author

Choose a reason for hiding this comment

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

探索をするときの時間計算量の話で、setはhashで探索を、listは前から順に探索をしているからだと理解しています。ただ実は、step1~step3をやっている間はこれについて意識していなかったです。他の方のレビューを見てから調べたりして把握しました。

return True
head_list.append(head.val)
head = head.next

return False

"""step2をやった。step1で私が書いたコードと非常に似ていると感じた。違いはset()を使用していること、headをそのまま使用しないで他の変数に置いているというところか。後の違いは私のコードはvalで比較をしているのに対して解答はノードで比較している点だ。この場合はvalとnextの両方が一致しているかみているということなのだろうか。

Choose a reason for hiding this comment

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

setの要素にできるか否かは、pythonの場合はその要素がhashableであるかどうかによります。
pythonの場合、objectを継承したクラスは特別な事をしない限りはhashableになり、すべての対象が保持しているidの値がそのままhashとして使われます。
したがって、特別な実装をしていない限りは、valとnextが一致していてもidが異なっていれば別物として扱われます。


別解のフロイドの循環検出アルゴリズムは、今の段階で理解できていない。なんで、循環している時はfast.next.nextとslow.nextが同じになるという発送になるのだろうか"""

Choose a reason for hiding this comment

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

AとBの二人がN歩で一周できる池の周りをぐるぐる周るとします。
Aは一歩ずつ、Bは二歩ずつ進むとします。
AとBを任意の地点に配置して、同じ方向にスタートさせると、毎回一歩ずつ二人の距離は相対的に縮まるので、いつか同じ場所にいる時がくるはずです。

一方で、循環がない場合はBさんが先に家に帰っちゃう(fast is Noneになる)ので二人が会うことはないです。


class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
visited_node = set()
current_node = head

while current_node:

Choose a reason for hiding this comment

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

Copy link
Owner Author

Choose a reason for hiding this comment

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

変数に関してですね、参考にさせていただきます。

if current_node in visited_node:
return True
visited_node.add(current_node)
current_node = current_node.next

return False

class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
fast = head
slow = head

while fast and fast.next:
fast = fast.next.next
slow = slow.next

if fast == slow:
return True

return False

"""step3 いいのかはわからないけど、ほとんど暗記されていたので1分で書き終わりました。別解も1分程度で書き終わりました。"""

class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
current_node = head
visited_node = set()
Comment on lines +49 to +50
Copy link

Choose a reason for hiding this comment

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

node, visitedでも十分かもしれません。
参考: https://github.com/h1rosaka/arai60/pull/2/files#r1688258262


while current_node:
if current_node in visited_node:
return True

visited_node.add(current_node)
current_node = current_node.next

return False

class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
fast = head
slow = head

while fast and fast.next:
fast = fast.next.next
slow = slow.next

if fast == slow:
return True

return False