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
188 changes: 188 additions & 0 deletions 142. Linked List Cycle II.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# step1
問題は142. Linked List Cycleとほとんど同じ?outputが具体的なnode番号にすればよい?

前回のコード
```python
class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
visited = set()
node = head
while node is not None:
if node in visited:
return True
visited.add(node)
node = node.next
return False
```

if node in visitedのところで何番目の値かを見る方法があるかな?
(そういえばsetって重複が許されないからテストケースによっては上手くいかなそう)

https://docs.python.org/ja/3/library/stdtypes.html#set

使えそうなメソッドはpopぐらい?1つずつ出して確認する方法?
>https://docs.python.org/ja/3/library/stdtypes.html#set
>オブジェクトの順序なしコレクションです。

順序のある配列かリストを使うのかな?

配列とリストの違いがあいまいなので調べる。
https://docs.python.org/ja/3/library/stdtypes.html#lists

配列arrayは標準ライブラリをimportして使うもの。

タプル:イミュータブルなリスト(https://docs.python.org/ja/3/library/stdtypes.html#tuples)

辞書:key valueでの保存

処理イメージ

- visitedのリストを作る
- headの値でループ
- ループの条件はNoneが来るまで。
- if node in visiitedのとき
- ループでvisited[i] == node になる iの値を探す。
- visitedが3,2,0,-4 でnodeが2のとき、i=1
- retunr tail connects to node index i
- ifの条件に入らなかったらnode = node.nextとvisited.append(node)

```python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None

class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
visited = []
node = head
while node is not None:
if node in visited:
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 に特定の値が含まれているかを確認するとき、すべての要素を一つ一つ調べなければなりません。これには時間がかかります。時間計算量は O(n) となります。

set を使用すると、特定の値が含まれているかを確認するとき、高速に調べることができます。時間計算量は O(1) となります。

配列・ハッシュテーブルあたりのデータ構造について調べ、余裕があれば CPython の set の実装を参考にされるとよいと思います。

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.

ありがとうございます、時間計算量の理解もあいまいだったので調べなおしました。
配列ハッシュテーブルあたりもイメージは湧きましたが衝突の回避方法のあたりが腑に落ちてないので読み直してみます

https://qiita.com/alswnd/items/428014509e52297b3a1b

for i in visited:
if visited[i] == node:
print("tail connects to node index" + i)
node = node.next
visited.append(node)
```
```
TypeError: list indices must be integers or slices, not ListNode
~~~~~~~^^^
if visited[i] == node:
Line 14 in detectCycle (Solution.py)
result = Solution().detectCycle(head)
Line 44 in _driver (Solution.py)
~~~~~~~^^
_driver()
Line 71 in <module> (Solution.py)
```

returnでprintを返すのかな?
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

return で print を返すという表現に違和感を感じました。

参考までに、関数の return 文で、 print 関数を返すとこのようになります。

C:\Program Files\Microsoft Visual Studio\2022\Community>python
Python 3.12.10 (tags/v3.12.10:0cc8128, Apr  8 2025, 12:21:36) [MSC v.1943 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> def f():
...     return print
...
>>> f()
<built-in function print>

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.

ありがとうございます、問題の理解不足で変な操作をしようとしていました。
printのオブジェクトがそのまま返ってしまうのですね

→問題文読んだらサイクルのbeginsを返すだった。サイクルの開始はif node in visitedの時点でのnode?
```python
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
visited = []
node = head
while node is not None:
if node in visited:
return node
# for i in range(len(visited)):
# print(i)
# if visited[i] == node:
# return print("tail connects to node index " + str(i))
visited.append(node)
node = node.next
```
自分は問題文の読み違いや取り違いが多い気がする。

# step2

他の人のPRなど見てみる.

https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.jfs03xpyyrfl


https://github.com/Nbotter/leetcode-easy-swe-practice/pull/12

- is not None と ==について

→https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.45ot5ov2xt6j

https://github.com/komdoroid/arai60/pull/9/changes#r2609582607

https://discord.com/channels/1084280443945353267/1307605446538039337/1309221770418454531

>速度の話をすると、Python は C などの50倍くらい遅いので本当に速くしたいならば言語を変えるのも選択の一つです。
速度的にはisのほうがわずかに早いらしい。

- return false入れてないけどいいのか?

→AI回答「Pythonはwhileを抜けた後、return None を省略しても暗黙的に None を返すので動きます。ただし明示的に書くほうが読みやすいです。」

- nodeに代入する理由は?

→AI回答「node = head に代入する理由head を直接動かすと、元のリストの先頭への参照を失うためです。node という別変数を使って走査します。」

→まだ参照とかをちゃんと理解しきれていなさそう。node = headのタイミングではnodeとheadは同じオブジェクト。node = node.nextとしたタイミングで右辺の計算結果のオブジェクトへの参照がnodeに入る。headはListNodeのオブジェクトだが、head.valは具体的な数値、head.nextは他のlistnodeへの参照。元のリストの先頭への参照は慣習的に残しているっぽい。
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

head.valもintのオブジェクトですよ。変数は全てオブジェクトへの参照です。

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でもいいのか?

→重複した値が来ると考えた場合にlistのほうが良い?

→AI回答「setに入れているのはnode(オブジェクト自体)であってnode.valではありません。例えばval=2のノードが2つあっても、それぞれ別のオブジェクトなのでid()が異なり、setでは別物として扱われます。」

→>>(そういえばsetって重複が許されないからテストケースによっては上手くいかなそう)

→nodeに入っているのはオブジェクト自体なので上手くいく。if node in visitedで見ているのはオブジェクトのidが合致しているかどうか。なので同じ値が入ってきてもオブジェクトidが違うので上手くいく。はず。

→前回深堀できなかった個所も深堀できて理解が深まった。やっぱりオブジェクトのところでもう一度読んでおく。

https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.wrv8idqm5j2b

- 計算量とかの話は全く理解できていないのでこの機会に理解しておく

→https://qiita.com/take-yoda/items/661d5a2b6fc2e5155309

データ量nが増えた時にどれだけ処理時間が増えるか。

https://amdlaboratory.com/amdblog/python%E3%81%A7%E5%AD%A6%E3%81%B6%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%E3%81%A8big-o-notationbig-o-%E8%A8%98%E6%B3%95/



# step3

```python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None

class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
print(id(head))
node = head
print(id(node))
visited = set()
while node is not None:
if node in visited:
return node
print(id(node))
# setはadd listはappend
visited.add(node)
node = node.next
# print(id(visited))
```

```python
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
node = head
visited = set()
while node:
if node in visited:
return node
visited.add(node)
node = node.next
```