Skip to content

Create 141. Linked List Cycle.md#2

Open
brood0783 wants to merge 1 commit into
mainfrom
141.-Linked-List-Cycle
Open

Create 141. Linked List Cycle.md#2
brood0783 wants to merge 1 commit into
mainfrom
141.-Linked-List-Cycle

Conversation

@brood0783
Copy link
Copy Markdown
Owner

@brood0783 brood0783 commented Jul 3, 2025

Copy link
Copy Markdown

@huyfififi huyfififi left a comment

Choose a reason for hiding this comment

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

良いと思います 👍

私はArai 60はやっていないのでよくわかりませんが、Arai 60は体感かなり難しく、序盤からハードな問題が続くような気がするので、かなりコーディングに慣れている人でないと苦労するような印象があります。壁が高すぎると感じたら、Easy問題をテキトーに見繕ってレビュー依頼するのでも良いかな、と老婆心ながら思います。

## 考えたこと
・visitedリストを作って、そこに訪問済みフラグを格納していく。訪問済みのノードに再び訪問したら、走査をやめてTrueを返す。
・whileの正式な書き方をど忘れ
・6通り解法を考えたが、どれもpassせず
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.

ありがとうございます!
次回からは、思考過程も含めてどういう流れで解法を検討していったのか、数点は書こうと思います!


## 実際と推定
・時間計算量
leetcode側で実行時間が55msと表示される。サーバー側でシングルスレッド1GHzの処理が可能と仮定して。ユーザーは大体500万人いるらしい(https://www.reddit.com/r/leetcode/comments/1g70avn/how_many_users_does_leetcode_have/)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

貼ってあるRedditでは、ランキングに参加している人数の話がされており、ある瞬間にサーバに負荷をかけているユーザの数とは異なると思いますが、いかがでしょう。

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.

おっしゃる通りです。アクティブユーザーもログインだけしている可能性があり、この議論の仕方はよくないです。
負荷(load)をかけているという情報で検索しましたが、該当するものがなさそうですね。後のコメントで、leetcodeで表示される処理時間はアテにならないという指摘も頂きましたので、推定はやめておこうと思います。

さらに、他の数百問の判定もしているため、アーキテクチャどうなってるんだろうという疑問がある。シンプルなものだと予想はされている。(https://github.com/sayamalvi/leetcode-backend-architecture-example)

・空間計算量
また、Leetcode側でのメモリ使用量は20.30 MBと表示される。このメモリ使用量は多い気がする。
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LeetCodeのサーバ上での実行時間とメモリ使用量は、同じ回答でもかなりブレがありあまり信用できない印象ですね。

set集合の作成にO(1)、whileで入力リストの要素数O(n)、ループごとにheadとset集合visitedの照合でO(1)で、O(1)+O(n)*O(1)=O(n)。

・空間計算量
headリスト用にリストの要素数O(n)、visitedのsetリスト作成にO(n)でO(n)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

setlistは別のものであるとの理解なので、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.

完全に素通りしてました...。set集合が正しいですね

visited.add(head)
head = head.next
```
まず訪問済みノードがない場合(リストがサイクルを持たない場合)、Noneが返ってFalseとして扱われると考えた。また、訪問済みノードがある場合(リストがサイクルを持つ場合)、headが返るが、hasCycleの返り値は、Noneかboolなので、ノードの要素が返る場合はTrue扱いされていると考えた。
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LeetCode内部でどのような処理をしているのかはわかりませんが、おそらく返り値をboolとして評価しているのでしょうね。

class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None


print(bool(None))  # False
print(bool(ListNode(0)))  # True

さておき、関数の型ヒントにboolを返すと書いているので、TrueFalseを返した方が誤解がないと思います。

class Solution:
    def hasCycle(self, head: Optional[ListNode]) -> bool:
        visited = set()
        while head:
            if head in visited:
                return True
            visited.add(head)
            head = head.next
        return False

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.

boolを返すのはもちろんです!headは悪い例ですが、推測が大方合っていたようでよかったです。

```
同じ名前(head)でも役割が変わる書き方が勉強になります。イテレータから、ノードの要素になってる。

headという命名に関してですが、回答上も同じ名前の使用で良い気がする。リスト形式にheadって名前自体が個人的にナンセンスですが、問題設定に乗っかる以上は変えなくて良いかなとなりました。でも、作問者もListって名前にしようとしてPythonでリスト形式を定義するときとの紛らわしさを感じて、この名前に仕方なくしたのかもしれない。
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

headlistを指しているわけではなくて、Linked Listの先端のNodeを指しているのでheadという命名で語弊がないように思います。

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.

他2名のreviewerの方からも同意があるように、ノードをリストと勘違いしておりました。ご指摘ありがとうございます。headで問題ないです。
より美しくするという点で、ryosuketcさんが後ほどご指摘のように、nodeを新たに定義してheadを代入します。

さらに、他の数百問の判定もしているため、アーキテクチャどうなってるんだろうという疑問がある。シンプルなものだと予想はされている。(https://github.com/sayamalvi/leetcode-backend-architecture-example)

・空間計算量
また、Leetcode側でのメモリ使用量は20.30 MBと表示される。このメモリ使用量は多い気がする。
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LeetCode のメモリ使用量よりは、空間計算量 (Big O 記法) と、各要素のメモリ消費から大雑把に空間計算量を見積もれるとよいと思いました。
https://stackoverflow.com/questions/449560/how-do-i-determine-the-size-of-an-object-in-python

Copy link
Copy Markdown
Owner Author

@brood0783 brood0783 Jul 6, 2025

Choose a reason for hiding this comment

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

ありがとうございます。送っていただいたsys.getsizeof()関数を用いて、とりあえず以下のように手元で検証しました。
空リストの場合を除いて、1要素平均76MBbytesで線形に比例します。空間計算量のO(n)とも合致する結果になりました。他にも考慮すべきものはありますが、まずはリストの要素に限定して見積もりました。

Test 1: 基本的なサイクル
  入力(先頭5要素): [3, 2, 0, -4], pos=1
  結果: True
  全体メモリ: 304 bytes (4ノードまで)

Test 2: 2要素のサイクル
  入力(先頭5要素): [1, 2], pos=0
  結果: True
  全体メモリ: 152 bytes (2ノードまで)

Test 3: 単一要素、サイクルなし
  入力(先頭5要素): [1], pos=-1
  結果: False
  全体メモリ: 76 bytes (1ノードまで)

Test 4: 中間でサイクル
  入力(先頭5要素): [1, 2, 3, 4, 5], pos=2
  結果: True
  全体メモリ: 380 bytes (5ノードまで)

Test 5: 空リスト
  入力(先頭5要素): [], pos=-1
  結果: False
  全体メモリ: 0 bytes (0ノード) - 空リスト
  head の値: None (None)
  sys.getsizeof(head): 16 bytes

Test 6: 大規模リスト
  入力(先頭5要素): [0, 1, 2, 3, 4]..., pos=999
  結果: True
  全体メモリ: 76000 bytes (1000ノードまで)


## 実際と推定
・時間計算量
leetcode側で実行時間が55msと表示される。サーバー側でシングルスレッド1GHzの処理が可能と仮定して。ユーザーは大体500万人いるらしい(https://www.reddit.com/r/leetcode/comments/1g70avn/how_many_users_does_leetcode_have/)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

時間計算量を含め、計算量全般についてはこのあたりにあります。
https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.1itsm36fdjze

```python
class Solution:
pos = -1
length = len(head)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

len(head) は自明なのでわざわざ変数に置く必要はないと思います。

Comment on lines +16 to +17
while(int i=0 : i =< length-1 : i++){
while(int j=0 : j =< length(visited)-1 : j++)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

この辺は Python syntax ではないように思います。

```python
class Solution:
pos = -1
length = len(head)
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 は LinkedList の先頭 (の 1 つの ListNode) なので、これはちょっと私の感覚が間違っているかもしれないですが、head の長さを求める、というのにちょっと違和感がありました (LinkedList の長さ、であればわかるのですが)。

https://stackoverflow.com/questions/31333462/finding-the-length-of-a-linked-list-in-python

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.

もともと、headがListであるという誤解から生じている操作なので、おそらくエラーが起きるかなと思います。誤解が解けた今では、同様に違和感を持ちます。

参照リンクありがとうございます。1つ目のAnswerのように、whileをつけて関数内でノードを辿らないと長さをカウントできないというのは完全に同意いたします。

while head:
if head in visited:
```
同じ名前(head)でも役割が変わる書き方が勉強になります。イテレータから、ノードの要素になってる。
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 も、ノードの要素だと思います (先頭のノード要素であるというだけ)。

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.

ありがとうございます。ここら辺を感覚で捉えてしまっていたので、調べておきます。

while head:
if head in visited:
```
同じ名前(head)でも役割が変わる書き方が勉強になります。イテレータから、ノードの要素になってる。
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 はあくまでも先頭という意味なので、これを更新していくのはどうかなと感じます。私なら node = head として node を更新すると思います。

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.

あと個人的には、head はあくまでも先頭という意味なので、これを更新していくのはどうかなと感じます。私なら node = head として node を更新すると思います。

ありがとうございます!「nodeを再定義するのはめんどくさいな」と思っていましたが、代入なら1行で終わりますね。以下のコードで3 stepsやり直しました!ヒントをくださり、ありがとうございます!

class Solution:
    def hasCycle(self, head: Optional[ListNode]) -> bool:
        node = head
        visited = set()
        while node:
            if node in visited:
                return True
            visited.add(node)
            node = node.next
        return False

while head:
if head in visited:
```
同じ名前(head)でも役割が変わる書き方が勉強になります。イテレータから、ノードの要素になってる。
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

headListNode のままではないでしょうか。

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.

おっしゃる通りです!headの役割はListNodeのままで、whileでheadがある限りたどっている認識です!

Comment on lines +16 to +17
while(int i=0 : i =< length-1 : i++){
while(int j=0 : j =< length(visited)-1 : j++)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

while の文法をC++やJavaScriptのものと混同していると見受けられます。

return True
visited.add(head)
head = head.next
```
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 False が必要ではないでしょうか?

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.

必要です!return FalseがないとNoneが返ってきます。気付ける範囲だったので、場合分けをそれぞれ満たしているか、次回からは注意します。以下のコードで3 stepsやり直しました!ありがとうございます!

class Solution:
    def hasCycle(self, head: Optional[ListNode]) -> bool:
        node = head
        visited = set()
        while node:
            if node in visited:
                return True
            visited.add(node)
            node = node.next
        return False


## 実際と推定
・時間計算量
leetcode側で実行時間が55msと表示される。サーバー側でシングルスレッド1GHzの処理が可能と仮定して。ユーザーは大体500万人いるらしい(https://www.reddit.com/r/leetcode/comments/1g70avn/how_many_users_does_leetcode_have/)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LeetCode の実行時間はブレがあるため、あまり信用しないほうがよいと思います。どうしても実行時間を計測したい場合は、手元で複数回実行して時間を計測し、中央値を取ったほうがよいと思います。

Copy link
Copy Markdown
Owner Author

@brood0783 brood0783 Jul 6, 2025

Choose a reason for hiding this comment

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

ありがとうございます!
気になる場合は手元で複数回計測のち、中央値を取りたいと思います。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants