Create 141. Linked List Cycle.md#2
Conversation
| ## 考えたこと | ||
| ・visitedリストを作って、そこに訪問済みフラグを格納していく。訪問済みのノードに再び訪問したら、走査をやめてTrueを返す。 | ||
| ・whileの正式な書き方をど忘れ | ||
| ・6通り解法を考えたが、どれもpassせず |
There was a problem hiding this comment.
思考過程もメモに残してシェアしていただくのがオススメです、レビュワーの方々からフィードバックを貰っての軌道修正のチャンスが増えると思うので
There was a problem hiding this comment.
ありがとうございます!
次回からは、思考過程も含めてどういう流れで解法を検討していったのか、数点は書こうと思います!
|
|
||
| ## 実際と推定 | ||
| ・時間計算量 | ||
| leetcode側で実行時間が55msと表示される。サーバー側でシングルスレッド1GHzの処理が可能と仮定して。ユーザーは大体500万人いるらしい(https://www.reddit.com/r/leetcode/comments/1g70avn/how_many_users_does_leetcode_have/) |
There was a problem hiding this comment.
貼ってあるRedditでは、ランキングに参加している人数の話がされており、ある瞬間にサーバに負荷をかけているユーザの数とは異なると思いますが、いかがでしょう。
There was a problem hiding this comment.
おっしゃる通りです。アクティブユーザーもログインだけしている可能性があり、この議論の仕方はよくないです。
負荷(load)をかけているという情報で検索しましたが、該当するものがなさそうですね。後のコメントで、leetcodeで表示される処理時間はアテにならないという指摘も頂きましたので、推定はやめておこうと思います。
| さらに、他の数百問の判定もしているため、アーキテクチャどうなってるんだろうという疑問がある。シンプルなものだと予想はされている。(https://github.com/sayamalvi/leetcode-backend-architecture-example) | ||
|
|
||
| ・空間計算量 | ||
| また、Leetcode側でのメモリ使用量は20.30 MBと表示される。このメモリ使用量は多い気がする。 |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
setとlistは別のものであるとの理解なので、setリスト、はやや語弊がある気がします。
There was a problem hiding this comment.
完全に素通りしてました...。set集合が正しいですね
| visited.add(head) | ||
| head = head.next | ||
| ``` | ||
| まず訪問済みノードがない場合(リストがサイクルを持たない場合)、Noneが返ってFalseとして扱われると考えた。また、訪問済みノードがある場合(リストがサイクルを持つ場合)、headが返るが、hasCycleの返り値は、Noneかboolなので、ノードの要素が返る場合はTrue扱いされていると考えた。 |
There was a problem hiding this comment.
LeetCode内部でどのような処理をしているのかはわかりませんが、おそらく返り値をboolとして評価しているのでしょうね。
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
print(bool(None)) # False
print(bool(ListNode(0))) # Trueさておき、関数の型ヒントにboolを返すと書いているので、TrueかFalseを返した方が誤解がないと思います。
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 FalseThere was a problem hiding this comment.
boolを返すのはもちろんです!headは悪い例ですが、推測が大方合っていたようでよかったです。
| ``` | ||
| 同じ名前(head)でも役割が変わる書き方が勉強になります。イテレータから、ノードの要素になってる。 | ||
|
|
||
| headという命名に関してですが、回答上も同じ名前の使用で良い気がする。リスト形式にheadって名前自体が個人的にナンセンスですが、問題設定に乗っかる以上は変えなくて良いかなとなりました。でも、作問者もListって名前にしようとしてPythonでリスト形式を定義するときとの紛らわしさを感じて、この名前に仕方なくしたのかもしれない。 |
There was a problem hiding this comment.
headはlistを指しているわけではなくて、Linked Listの先端のNodeを指しているのでheadという命名で語弊がないように思います。
There was a problem hiding this comment.
他2名のreviewerの方からも同意があるように、ノードをリストと勘違いしておりました。ご指摘ありがとうございます。headで問題ないです。
より美しくするという点で、ryosuketcさんが後ほどご指摘のように、nodeを新たに定義してheadを代入します。
| さらに、他の数百問の判定もしているため、アーキテクチャどうなってるんだろうという疑問がある。シンプルなものだと予想はされている。(https://github.com/sayamalvi/leetcode-backend-architecture-example) | ||
|
|
||
| ・空間計算量 | ||
| また、Leetcode側でのメモリ使用量は20.30 MBと表示される。このメモリ使用量は多い気がする。 |
There was a problem hiding this comment.
LeetCode のメモリ使用量よりは、空間計算量 (Big O 記法) と、各要素のメモリ消費から大雑把に空間計算量を見積もれるとよいと思いました。
https://stackoverflow.com/questions/449560/how-do-i-determine-the-size-of-an-object-in-python
There was a problem hiding this comment.
ありがとうございます。送っていただいた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/) |
There was a problem hiding this comment.
時間計算量を含め、計算量全般についてはこのあたりにあります。
https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.1itsm36fdjze
| ```python | ||
| class Solution: | ||
| pos = -1 | ||
| length = len(head) |
| while(int i=0 : i =< length-1 : i++){ | ||
| while(int j=0 : j =< length(visited)-1 : j++) |
| ```python | ||
| class Solution: | ||
| pos = -1 | ||
| length = len(head) |
There was a problem hiding this comment.
head は LinkedList の先頭 (の 1 つの ListNode) なので、これはちょっと私の感覚が間違っているかもしれないですが、head の長さを求める、というのにちょっと違和感がありました (LinkedList の長さ、であればわかるのですが)。
https://stackoverflow.com/questions/31333462/finding-the-length-of-a-linked-list-in-python
There was a problem hiding this comment.
もともと、headがListであるという誤解から生じている操作なので、おそらくエラーが起きるかなと思います。誤解が解けた今では、同様に違和感を持ちます。
参照リンクありがとうございます。1つ目のAnswerのように、whileをつけて関数内でノードを辿らないと長さをカウントできないというのは完全に同意いたします。
| while head: | ||
| if head in visited: | ||
| ``` | ||
| 同じ名前(head)でも役割が変わる書き方が勉強になります。イテレータから、ノードの要素になってる。 |
There was a problem hiding this comment.
head も、ノードの要素だと思います (先頭のノード要素であるというだけ)。
There was a problem hiding this comment.
ありがとうございます。ここら辺を感覚で捉えてしまっていたので、調べておきます。
| while head: | ||
| if head in visited: | ||
| ``` | ||
| 同じ名前(head)でも役割が変わる書き方が勉強になります。イテレータから、ノードの要素になってる。 |
There was a problem hiding this comment.
あと個人的には、head はあくまでも先頭という意味なので、これを更新していくのはどうかなと感じます。私なら node = head として node を更新すると思います。
There was a problem hiding this comment.
あと個人的には、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)でも役割が変わる書き方が勉強になります。イテレータから、ノードの要素になってる。 |
There was a problem hiding this comment.
おっしゃる通りです!headの役割はListNodeのままで、whileでheadがある限りたどっている認識です!
| while(int i=0 : i =< length-1 : i++){ | ||
| while(int j=0 : j =< length(visited)-1 : j++) |
There was a problem hiding this comment.
while の文法をC++やJavaScriptのものと混同していると見受けられます。
| return True | ||
| visited.add(head) | ||
| head = head.next | ||
| ``` |
There was a problem hiding this comment.
必要です!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/) |
There was a problem hiding this comment.
LeetCode の実行時間はブレがあるため、あまり信用しないほうがよいと思います。どうしても実行時間を計測したい場合は、手元で複数回実行して時間を計測し、中央値を取ったほうがよいと思います。
There was a problem hiding this comment.
ありがとうございます!
気になる場合は手元で複数回計測のち、中央値を取りたいと思います。
This problem
https://leetcode.com/problems/linked-list-cycle/description/
Next
https://leetcode.com/problems/linked-list-cycle-ii/description/
言語
Python 3