Skip to content
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
150 changes: 150 additions & 0 deletions 141.Linked_List_Cycle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
1st.
C++で解いた経験のある問題。fast, slowの二つのポインタを用意しheadからスタートする。
fastがslowに追いついたときループがある。逆に追い付くことなくslowがnullptrまでいった場合ループはないと言える。
というのが基本的な方針として重いついたのでその方針で実装してみる。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

良いと思います。Discordも漁ってみるといいかもしれません。

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.

ありがとうございます。
Discordも見てみたいと思います。

基本的にはこれでいけていると思う(フロイドの循環検出法というよう)
しかし、入力が[]のときやノードが一つのときも確認出来ているかが少し分かりにくい?
また、setで探索したノードを保持して以前探索していた場合はTrueという方針がある。
こちらの方が直感敵だし、間違えなさそうではある。しかし、setで保持するぶんメモリを使う?

```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:

fast = head
slow = head

while fast and fast.next:

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

if fast == slow:
return True

return False
```

```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:
visited = set()

current_node = head
while current_node:
if current_node in visited:
return True
visited.add(current_node)
current_node = current_node.next

return False
```

2nd.
current から nodeに変更した。
visitedをseenにする案も見かけたが個人的にvisitedのほうが分かりやすい気がしたのでそのままにした。
set()を使う方法は空間計算量はO(n):nは要素数であるがかなり分かりやすく書きやすい。

```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:
visited = set()
node = head
while node:
if node in visited:
return True
visited.add(node)
node = node.next
return False
```

```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:
fast = head
slow = head

while head and head.next:
head = head.next.next
slow = slow.next

if head == slow:
return True
return False
```

3rd.
```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:
visited = set()
node = head
while node:
if node in visited:
return True
visited.add(node)
node = node.next
return False
```

```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:
fast = head
slow = head

while fast and fast.next:
fast = fast.next.next
slow = slow.next
if fast == slow:
return True
return False
```

tk-hirom さんのレポジトリより
https://github.com/tk-hirom/Arai60/pull/1/commits/967ba6e39e0f6fd44a044778596f7dcd13ad0160
setを使った実装ができるかをみているよう。
ここでsetであることが大事でlistだと検索に時間計算量O(n)かかるが、setだとO(1)で検索できる。
今回のように順序が関係ない場合setのほうがよい。

疑問:Pythonのlistとsetでは今回の場合使用するメモリの量はどちらが大きいのか

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.

コメントありがとうございます。
手元でためしてみました。
listはその要素への参照を保存しているだけなのに対して、setはハッシュ値を計算しているためにメモリを使うことが分かりました。

  • setはハッシュテーブルを保持すること。
  • このハッシュテーブルは衝突を防ぐために要素数よりも多めに確保する必要があること。
  • このテーブルはある程度要素が追加されると一致してしまう可能性が上がるのでさらに拡張される(リハッシュ)されるのでより大きくなること。
    の3つが主な原因という理解であっているでしょうか。

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.

ご確認ありがとうございます。


予想:setのほうが重複するデータや順序の情報を持たないので小さい?
⇒こういったことはどのように調べたら良いのか
Comment on lines +141 to +150

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

全体的に良いと思います!

この問題では具体的にどれくらいかは分かりませんが、10万要素でリストとsetを作った場合、setの方がリストより6倍くらいメモリを使ってるそうです。
https://www.tsuyukimakoto.com/blog/2019/07/16/python_list_set_array_performance/

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.

コメントありがとうございます。
そのようですね。
下のコメントでodaさんに教えていただいたように手元で試してみたところ5, 2倍程度でした。