-
Notifications
You must be signed in to change notification settings - Fork 0
142. Linked List Cycle II #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
"""step1 | ||
141と似たような問題、違いは答えの出力が循環が始まる位置を求められていること。 | ||
以下のように解こうと思う。 | ||
set()で置いてwhile文を用いて循環しているノードを探し出す。 | ||
これだと位置を返すのが難しいな。 | ||
dict形式で位置とノードを格納すればできるかも。 | ||
|
||
インデックスとなるposをkeyとして、nodeをvalueに格納すれば、node.nextをしてdictの中に入っているかを確認すればよい。 | ||
|
||
nullって書いてあるけどpythonだとNoneだよな? | ||
""" | ||
|
||
class Solution: | ||
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
visited_node = {} | ||
node = head | ||
pos = 0 | ||
|
||
while node: | ||
if node in visited_node.values(): | ||
return node | ||
visited_node[pos] = node | ||
pos += 1 | ||
node = node.next | ||
|
||
return None | ||
|
||
"""step2 | ||
141のコードレビューで指摘された、最初にアルゴリズムを言語化するというのはできたが、時間計算量と空間計算量を概算するという過程を忘れていたので、次回では忘れずにやりたい。 | ||
解答を見る感じだと141みたいにフロイドの循環アルゴリズムを使う方法があるっぽい。だけど理由がわからない。 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. フロイドの循環アルゴリズムはソフトウェアエンジニアの常識には含まれていないと思います。 set() を用いた解法が書ければ十分だと思います。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. そうなんですね。ちなみに、常識に含まれていないアルゴリズムや解法を調べるのは趣味の範疇としてそこまで気にしなくて良いものなのでしょうか。それとも常識がある人たちは、趣味の範疇と切り捨てずに出てきたものはくまなく調べ上げるものなのでしょうか? 常識がある人たちの意識がどこにあるのかをお聞きしたいです。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 人によると思います。自分の場合は、気になったものは調べますし、そうでないものは頭の片隅に置いておく程度にとどめると思います。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 面接官から見ると、速い人と遅い人で速度が10倍違うので、速い人のために時間つなぎがしたくなることがあるんですよ。そういうときに、パズル要素があると、パズルを説明したりしていると時間が使えるので、そこが評価ポイントでなかったとしても便利なんです。また、受けている人を歓待したいという気持ちがあります。少なくとも、自社にいい印象を持っている人を怒らせて帰す必要はないですからね。転職が多い業界でいつ一緒に働くかは分からないわけですし。 |
||
|
||
https://github.com/h1rosaka/arai60/pull/4#discussion_r1722542513 プライベートメソッドだとアンダースコアをつけるのが普通なんですね。 | ||
|
||
というか、141ではset()でやって、しかも最初の方針でもset()を使うようにと書いているのになぜか今回のケースだとできなくねと判断してdict{}でやってしまっている。他のデータ構造でも代用できたと、ポジティブに捉えることができるが計算も遅いし、実装としてはあまりよろしくない。 | ||
あ、これは問題を読み間違えていてnodeを返すのではなく位置を返すと勘違いしていることから起きたことですね。結局テストケースを試してみて位置を返すのではなくnodeを返すんじゃんと気づき、その場でdictをささっと修正して提出したのが原因なようです。落ち着きましょう。 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. これは重要な気づきだと思います。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 前回のコードレビューで、思考ログを書くと良いとアドバイスされたのでやってみました。見直しをするときにかなり役立ちそうですね。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 主題と関係ないのですが、この問題に関しては問題文が少し理解しづらいので、気持ちはわかります。。。 |
||
|
||
dictとset()で解いた場合、それぞれで比較してみましたが速度の違いが断然違いますね。なんでかを調べます。 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. これ私もわからなかったので少し調べてみました。 このサイトに下記のように記載があり、確かに重複しうるからハッシュにできなくて実質リストみたいになってて一個ずつ確認するしかないからinが遅いのかな、と私は納得しました。ハッシュが速い理由はこのサイトがわかりやすいです。
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. これは、dictで解く際に There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. visited_nodes: dict[int, ListNode]の方がvisited_nodes: dict[ListNode, int]より速い理由について調べているのですが、中々良い考察を見つけられません。理由をご存知でしたら教えていただきたいです、、、。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 上記の議論はPythonの辞書のkeyとvalueの探索の違いについて書かれています。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. なるほどそういうことなのですね。ずっとintの方がListNodeよりも速いという理解をしていたのでその理由を考えていました。そうではなくて探索をするときにkeyを見るか、valueを見るかという話ということなのですね。ありがとうございます。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ちなみに #4 (comment) で記載されている「より速い」の順序が逆になっています! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. タイポですね、、、指摘ありがとうございます! |
||
|
||
このステップでは、set()に直した場合でやった。もう一つの別解としてフロイドの循環法を使っても解いてみた。多くの解答では2回目にポインタを動かす操作(コードで言うと2回目のwhile文)をするときにheadを動かしていたが、headを動かすことは可読性の観点から抵抗があったのでslowをもう一度初期化して解いた。コードの行数を減らすと言う意味では、初期化をせずにheadを使うべきだがそれを言ってしまうとfast = slow = headだったりそもそも最初に2変数を定義する意味も薄れてしまうなと感じたので、可読性を意識して初期化をした。 | ||
""" | ||
|
||
class Solution: | ||
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
visited_node = set() | ||
node = head | ||
while node: | ||
if node in visited_node: | ||
return node | ||
visited_node.add(node) | ||
node = node.next | ||
|
||
return None | ||
|
||
class Solution: | ||
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
fast = head | ||
slow = head | ||
|
||
while fast and fast.next: | ||
fast = fast.next.next | ||
slow = slow.next | ||
|
||
if fast == slow: | ||
slow = head | ||
while(fast != slow): | ||
fast = fast.next | ||
slow = slow.next | ||
return fast | ||
|
||
return None | ||
|
||
"""step3 | ||
両方の解放とも1分で解答 | ||
""" | ||
|
||
class Solution: | ||
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
visited_node = set() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nodesの方が良いかと思います。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 複数のオブジェクトを扱うときは変数名も気をつけた方が良さそうですね、ありがとうございます |
||
node = head | ||
|
||
while node: | ||
if node in visited_node: | ||
return node | ||
visited_node.add(node) | ||
node = node.next | ||
|
||
return None | ||
|
||
class Solution: | ||
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
fast = head | ||
slow = head | ||
|
||
while fast and fast.next: | ||
fast = fast.next.next | ||
slow = slow.next | ||
|
||
if fast == slow: | ||
slow = head | ||
while(fast != slow): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 全く気にしたことがなかったところです。ありがとうございます! |
||
fast = fast.next | ||
slow = slow.next | ||
|
||
return fast | ||
|
||
return None | ||
""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
複数の値が格納される変数の変数名は複数形で終えたほうが、中に複数の値が含まれていることが分かりやすくなり、読んでいる人にとって読みやすく感じられると思います。