Create 142. Linked List Cycle II.md#2
Conversation
| Line 71 in <module> (Solution.py) | ||
| ``` | ||
|
|
||
| returnでprintを返すのかな? |
There was a problem hiding this comment.
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>
There was a problem hiding this comment.
ありがとうございます、問題の理解不足で変な操作をしようとしていました。
printのオブジェクトがそのまま返ってしまうのですね
| visited = [] | ||
| node = head | ||
| while node is not None: | ||
| if node in visited: |
There was a problem hiding this comment.
list に特定の値が含まれているかを確認するとき、すべての要素を一つ一つ調べなければなりません。これには時間がかかります。時間計算量は O(n) となります。
set を使用すると、特定の値が含まれているかを確認するとき、高速に調べることができます。時間計算量は O(1) となります。
配列・ハッシュテーブルあたりのデータ構造について調べ、余裕があれば CPython の set の実装を参考にされるとよいと思います。
There was a problem hiding this comment.
ありがとうございます、時間計算量の理解もあいまいだったので調べなおしました。
配列ハッシュテーブルあたりもイメージは湧きましたが衝突の回避方法のあたりが腑に落ちてないので読み直してみます
|
|
||
| →AI回答「node = head に代入する理由head を直接動かすと、元のリストの先頭への参照を失うためです。node という別変数を使って走査します。」 | ||
|
|
||
| →まだ参照とかをちゃんと理解しきれていなさそう。node = headのタイミングではnodeとheadは同じオブジェクト。node = node.nextとしたタイミングで右辺の計算結果のオブジェクトへの参照がnodeに入る。headはListNodeのオブジェクトだが、head.valは具体的な数値、head.nextは他のlistnodeへの参照。元のリストの先頭への参照は慣習的に残しているっぽい。 |
There was a problem hiding this comment.
head.valもintのオブジェクトですよ。変数は全てオブジェクトへの参照です。
enari-k
left a comment
There was a problem hiding this comment.
set を使った実装、お疲れ様です!ロジックも合っていますし、まずは確実に動く解法を書けることが素晴らしいです。
実はこの問題、下の方に「空間計算量
以前、元googleのエンジニアにコーディングの模擬面接をしてもらったことがあるのですが、一つ解法を書いた後にそれより良い解法があるならば、たとえば今回の場合だと、空間計算量O(1)で書けますか?と聞いてくるからです。
以下、空間計算量O(1)で書く場合のアルゴリズムについての証明とコードを載せておきます。
証明
fastとslowの二つのポインターを用意して、fastを2歩ずつ、slowを1歩ずつ進めます。
すると、この二つがいずれ衝突します。ここで、
H:ループの開始地点
L:一ループの長さ
D:ループの開始地点から衝突地点まで
のように定義します。
fast = H + D + n * L
slow = H + D
となるはずです。ここで、fast = slow * 2が成立することから
H + D + n * L = 2 * (H + D)
より整理すると、
H = n * L - D
H = (n - 1) * L + (L - D)
となる。上記の式から先ほどの衝突地点から、H歩進んだ時に、ちょうどループしてループの開始地点に戻ることが分かります。よって、開始地点からH歩進ませるのとさっきの衝突地点からH歩進ませたものはちょうどループの開始地点で衝突するはずです。これによって、ループの開始地点は特定できます。
このアルゴリズムを用いることにより、時間計算量はO(N)、空間計算量はO(1)となります。
コード
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
fast = head
slow = head
isCycle = False
if head is None:
return None
while fast.next is not None and fast.next.next is not None:
fast = fast.next.next
slow = slow.next
if fast == slow:
isCycle = True
break
if not isCycle:
return None
slow = head
while fast != slow:
slow = slow.next
fast = fast.next
return fast
@enari-k
→視野や選択肢を広げるためにはほかの人のPRなど見ながら吸収していこうと思います コードもありがとうございます! |
解いた問題:https://leetcode.com/problems/linked-list-cycle-ii/
次解く:https://leetcode.com/problems/remove-duplicates-from-sorted-list/description/