-
Notifications
You must be signed in to change notification settings - Fork 0
142. Linked List Cycle II #3
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,104 @@ | ||
# step1 | ||
```python | ||
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
visited_nodes = set() | ||
current_node = head | ||
while current_node: | ||
if current_node in visited_nodes: | ||
return current_node | ||
visited_nodes.add(current_node) | ||
current_node = current_node.next | ||
return None | ||
``` | ||
#### 思考ログ | ||
- 問題文の文意(前回の141からとの違い、何を問うているのか)があまり読み取れなかった | ||
- 前回の問題との違いはBoolで返していた値をNodeにするくらいかなと考えたが、流石にそんな簡単なことあるのかと思った | ||
- とりあえず時間制限もあるので、Nodeを返すよう修正してみたところ通った | ||
- hashMapとtwo-pointerのどちらで解こうか考えたがシンプルなhashMapを選んだ | ||
|
||
# step1.5 | ||
```python | ||
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
fast = slow = head | ||
while fast and fast.next: | ||
fast = fast.next.next | ||
slow = slow.next | ||
if fast is slow: | ||
break | ||
if not fast or not fast.next: | ||
return None | ||
slow = head | ||
while fast is not slow: | ||
fast = fast.next | ||
slow = slow.next | ||
return fast | ||
``` | ||
#### 思考ログ | ||
- two-pointerでも解いてみる | ||
- こちらで解いてみると問題の意図に気付いた | ||
- hashMapは常にループの最初を検知できるが、two-pointerの場合ループ途中のノードで検知する可能性がある。 | ||
- 5分経っても解法がわからないのでaraiさんの解説動画を見る | ||
- フロイドの循環検出法というらしい | ||
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. フロイドの循環検出法はソフトウェアエンジニアの常識には含まれていないと思います。ただ、 LeetCode でコーディングやアルゴリズムの勉強をしている人は、なぜか知っているような気がします。 |
||
- https://ja.wikipedia.org/wiki/%E3%83%95%E3%83%AD%E3%82%A4%E3%83%89%E3%81%AE%E5%BE%AA%E7%92%B0%E6%A4%9C%E5%87%BA%E6%B3%95 | ||
- araiさんの解説で理論はわかったがどこまでの理解が必要なのか | ||
- このような問題がそのまま出るのか他のアルゴリズムを組み居合わせるような応用が出るのか | ||
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. ありがとうございます、自分の理解と同じことを確認できました! |
||
- 前回の問題の際も二つ解放があったがどちらの方がいいかなどは特に考えていなかった | ||
- 計算量の観点から考えてみる | ||
- hashMap | ||
- time complexityはo(n) | ||
- space complexityはo(n) | ||
- two-pointer | ||
- time complexityはo(n) | ||
- space complexityはo(1) | ||
- two-pointerの方がspace complexityが小さくなるので今回はtwo-pointerを採用する | ||
|
||
# step2 | ||
```python | ||
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
fast = slow = head | ||
while fast and fast.next: | ||
fast = fast.next.next | ||
slow = slow.next | ||
if fast is slow: | ||
break | ||
if not fast or not fast.next: | ||
return None | ||
slow = head | ||
while fast is not slow: | ||
fast = fast.next | ||
slow = slow.next | ||
return fast | ||
|
||
``` | ||
#### 思考ログ | ||
- not A is BとA is not Bのように、notのつける位置によってどう変わるのか | ||
- > Use is not operator rather than not ... is. While both expressions are functionally identical, the former is more readable and preferred: | ||
``` python | ||
# Correct: | ||
if foo is not None: | ||
# Wrong: | ||
if not foo is None: | ||
``` | ||
- https://peps.python.org/pep-0008 | ||
- pepに上記の記述があったのでpythonで推奨されているのはis notの方 | ||
|
||
# step3 | ||
```python | ||
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
fast = slow = head | ||
while fast and fast.next: | ||
fast = fast.next.next | ||
slow = slow.next | ||
if fast is slow: | ||
break | ||
if not fast or not fast.next: | ||
return None | ||
slow = head | ||
while fast is not slow: | ||
fast = fast.next | ||
slow = slow.next | ||
Comment on lines
+97
to
+99
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,slowとは違っていますが、 |
||
return fast | ||
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. t0hsumiさんと同様で、ポインタの再配置の後はslow, fastの差異はその役割のみで速度的な違いはないので別の変数を作ってコピーしてやるといいと思います。 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. https://github.com/pineappleYogurt/leetCode/pull/3/files#r1880502989 |
||
``` | ||
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. 他の方のコードを読むこと失念していました。 |
||
#### 思考ログ | ||
- エラー出さないで3回続けてを繰り返していると、間違えやすいところが見えてくる。 | ||
- 面接を想定して1文ずつここはどういう意図で書いているかを考えながら解けた。 |
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.
私の感じる出題意図はこういうものです。
本当にできない人もいるので、できたら簡単な問題にしたい。すぐに解ける人もいるのでそうだとしたら議論をすることによって、色々な能力を推し量りたい。本当に知りたいことは、仕事ができるかで、つまりは「コードの仕様を変えたいときに巨大なコードベースを掘って見つけ、該当箇所を変更する綺麗な案を作り、他のチームメイトにそれでうまくいくことを説明して、プロダクションに持っていくこと」なので、コードが書けるかどうかはあまり重要ではない。
最近だと、プログラミングコンテストの影響で、自分が書いたコードすら読めない人が多い。
そこで、「簡単な問題を出して見るが、一捻りしたアハ解答があるので、議論をしてみて、ヒントを出しながらフロイドの方法に到達すると、コミュニケーションが取れてコードが読めるかなどが確認できて良い」という思考で出ていると思われます。
https://docs.google.com/presentation/d/1Ny4kmHE2FZMI0AuPxImokweGoAE73RAGivjDJg0kG80/edit#slide=id.g22c5f8cce92_0_0
Uh oh!
There was an error while loading. Please reload this page.
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.
つまりは最終的に、『多少のヒントをもらいながら自力でアハ解答を導き出せる状態』ようになる必要があるのでしょうか?
仮にそうだとした場合、今の自分の解き方でarai60を解き切った時にその状態になれるのか、もしかするとやり方を変えるべきなのではと考えています。
今の自分は、ルールとして提示されていた
を元に以下のように解いています。
これを繰り返すごとでarai60で紹介されている解法に関しては覚えることはできるものの、odaさんが書かれているアハ解答というのができるようになるのかという不安があります。
アハ解答を思いつけるようになるには、1により時間をかけて自分で解答を思いつく必要があるのかなと考えましたが、今のやり方を続けていくことでアハ解答的な発想が身についていくのでしょうか?
それともそもそもこの視点がずれているのでしょうか?
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.
いや、私の意図としては、パズルが解けるかみたいなのはほとんど評価の対象になっていないです。
ただ、同じ問題を出しても5分で解く人と1時間かかっても解けない人がいるので、5分で解かれてしまった場合、出題者は時間が余って困ります。
そこで、時間をつなぎながら「コードの仕様を変えたいときに巨大なコードベースを掘って見つけ、該当箇所を変更する綺麗な案を作り、他のチームメイトにそれでうまくいくことを説明して、プロダクションに持っていくこと」ができるかを確認しに行きます。
そうすると、パズル的な他の解き方がある問題というのはとてもいいです。なぜかというと「パズル的な解き方を出題者が説明して、それを理解して実装してもらう」と、上の要素のうち「自然言語での説明を理解する」「変更案を作る」「コードの説明する」といった要素が自然に確認できるし、候補者がいい体験だったと思ってくれるからです。
面接官やハイアリングマネージャーの気持ちを考えてみましょう。
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.
確かにその意図で言うと、提示されているleetcodeのルールで解いていけば議論する力は養われていきそうです!
ありがとうございます、納得した上で進めていきそうです!