-
Notifications
You must be signed in to change notification settings - Fork 0
142. Linked List Cycle II #2
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,160 @@ | ||
| 1st. | ||
| 方針として141.Linked List Cycleと同様にsetで訪れたnodeを保持し、訪れていた場合そのnodeを返す。訪れていない場合はsetに追加しnodeを次に進めるという操作をnodeがNoneになるまで繰り返すという方針を思いつき実装した。 | ||
| 141を解いてから日が空いていないないためかスムーズに書くことが出来た。 | ||
| ```Python | ||
| # Definition for singly-linked list. | ||
| # class ListNode: | ||
| # def __init__(self, x): | ||
| # self.val = x | ||
| # self.next = None | ||
|
|
||
| class Solution: | ||
| def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| visited = set() | ||
| node = head | ||
| while node: | ||
| if node in visited: | ||
| return node | ||
| visited.add(node) | ||
| node = node.next | ||
| return None | ||
| ``` | ||
|
|
||
| 2nd. | ||
| 1st.の段階でフロイドの循環検知でも解けるか考えたが、循環していることは検知できても、fastがslowに追い付いたnodeがCycleの始まりとなっているnodeとは限らないためどうしようか迷い思いつかなかったため他の方の回答を見て実装した。 | ||
| (https://discord.com/channels/1084280443945353267/1246383603122966570/1252209488815984710) | ||
| を見て理解は出来たがこれを思いつくのは厳しそう | ||
| ```Python | ||
| # Definition for singly-linked list. | ||
| # class ListNode: | ||
| # def __init__(self, x): | ||
| # self.val = x | ||
| # self.next = 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: | ||
| break | ||
| else: | ||
| return None | ||
|
|
||
| fast = head | ||
|
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という変数の意味が変わっています。アルゴリズムを知っている人からすると自明ですが、初見だと戸惑うかもしれません。
Owner
Author
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. 私も以前同様のコメントをいただきました。
Owner
Author
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. コメントありがとうございます。 |
||
| while fast != slow: | ||
| fast = fast.next | ||
| slow = slow.next | ||
| return fast | ||
| ``` | ||
| 始めは下のように書いていた。 | ||
| ```Python | ||
| while fast and fast.next: | ||
| fast = fast.next.next | ||
| slow = slow.next | ||
|
|
||
| if fast == slow: | ||
| fast = head | ||
| while fast is not slow: | ||
| fast = fast.next | ||
| slow = slow.next | ||
| return fast | ||
|
|
||
| return None | ||
| ``` | ||
| しかし、whileの中のifが長くなるが見づらくなるので外に出すようにした(https://discord.com/channels/1084280443945353267/1221030192609493053/1225674901445283860) | ||
| while - else を使うのがしっくりきた。 | ||
|
|
||
| Discordを見ていくとsetを用いる方法の亜種といえると思うが再帰を使う方法もあると知った。 | ||
|
|
||
| その中で(https://github.com/h1rosaka/arai60/pull/4/files#diff-97a2b5510d65cd5c736cab9a3675eb2122bfe5e9ccbe491032aad6fee9d3f74d)での話は大変参考になった。 | ||
|
|
||
| 再帰の場合はstack overflowに注意する必要がある。これは無限再帰などでstackにdataをpushし続けることでおきる。 | ||
| * Pythonの場合は再帰呼び出しの上限回数がsys.getrecursionlimit()で確認出来る。環境依存だがデフォルトでは1000回のようで手元で試しても1000であった。(https://docs.python.org/ja/3/library/sys.html#sys.getrecursionlimit) | ||
| * setrecursionlimit()で変更もできるが大きくしすぎるとクラッシュする恐れがある。 | ||
| * C/C++でも大きくて10M程度であるようだ | ||
|
|
||
| 今回の例で言えばn個のnodeがcycleを持たずに並んでいた場合再帰はn回呼び出されstackにpushされることになるので入力nodeの大きさが大きくなるとstack over flowの恐れがあると考えられる。(LeetCodeのコードが実行される環境での再帰呼び出し回数の上限は分からない) | ||
|
|
||
| また,クイックソートで再帰を用いる場合、stack over flow対策として再帰は短い方からやる。長い方では末尾再帰最適化を行うなどの工夫があるよう。(https://nuc.hatenadiary.org/entry/2021/03/31#:~:text=%E7%9F%AD%E3%81%84%E6%96%B9%E3%81%8B%E3%82%89%E5%86%8D%E5%B8%B0%E3%81%97%E3%81%A6%E3%80%81%E9%95%B7%E3%81%84%E6%96%B9%E3%81%AF%E6%9C%AB%E5%B0%BE%E5%86%8D%E5%B8%B0%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%99%E3%82%8B%E3%81%93%E3%81%A8) | ||
|
|
||
| ```Python | ||
| # Definition for singly-linked list. | ||
| # class ListNode: | ||
| # def __init__(self, x): | ||
| # self.val = x | ||
| # self.next = None | ||
|
|
||
| class Solution: | ||
| def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| visited = set() | ||
|
|
||
| def _check_node(node): | ||
|
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. inner function の関数名の先頭には _ を付けなくてよいと思います。非 public な関数名には付けたほうがよいと思います。 https://peps.python.org/pep-0008/#method-names-and-instance-variables
https://google.github.io/styleguide/pyguide.html#3162-naming-conventions
Owner
Author
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. コメントありがとうございます。 |
||
| if node is None: | ||
| return None | ||
| if node in visited: | ||
| return node | ||
|
|
||
| visited.add(node) | ||
|
|
||
| return _check_node(node.next) | ||
|
|
||
| return _check_node(head) | ||
| ``` | ||
|
|
||
| 3rd. | ||
| set()とtwo pointer no2通りの方法について3回書けるまで行った。 | ||
| ```Python | ||
| # Definition for singly-linked list. | ||
| # class ListNode: | ||
| # def __init__(self, x): | ||
| # self.val = x | ||
| # self.next = None | ||
|
|
||
| class Solution: | ||
| def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| visited = set() | ||
| node = head | ||
|
|
||
| while node: | ||
| if node in visited: | ||
| return node | ||
| visited.add(node) | ||
| node = node.next | ||
|
|
||
| return None | ||
| ``` | ||
|
|
||
| ```Python | ||
| # Definition for singly-linked list. | ||
| # class ListNode: | ||
| # def __init__(self, x): | ||
| # self.val = x | ||
| # self.next = 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: | ||
| break | ||
| else: | ||
| return None | ||
|
|
||
| # breakした場合 | ||
| fast = head | ||
| while fast != slow: | ||
| fast = fast.next | ||
| slow = slow.next | ||
| return fast | ||
| ``` | ||
|
|
||
|
|
||
|
|
||
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.
while-else は Python に特徴的な文法です。
整え方にいくつか方法があるので、このあたりを見ておいてください。
https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.4qnnfvpo8ij5
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.
コメントありがとうございます。
参考にさせていただきます。