-
Notifications
You must be signed in to change notification settings - Fork 0
141. linked list cycle #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,85 @@ | ||
| ## 今回解いた問題と次に解く問題 | ||
| - 今回解いた問題: 141. Linked List Cycle(https://leetcode.com/problems/linked-list-cycle?envType=problem-list-v2&envId=xo2bgr0r) | ||
| - 次に解く問題: 20. Valid Parentheses(https://leetcode.com/problems/valid-parentheses?envType=problem-list-v2&envId=xo2bgr0r) | ||
| ## Step 1 | ||
| ### 考えたこと | ||
| - フロイドの循環検出法を見たことがあったが、とりあえず一度訪れたnodeをsetに保持しておいて、毎回確認する方法が確実なので書いてみる。時間計算量はO(n), 空間計算量はsetを用意するのでO(n) | ||
| - setの中にclassを入れることができるかわからなかったので、確認した。 | ||
| - `while True`は停止しないときが怖いので、使いたくないと感じたが、パッとループを回す方法が思いつかなかったので一度書いてみた。 | ||
| - | ||
| ```python | ||
| # Definition for singly-linked list. | ||
| # class ListNode: | ||
| # def __init__(self, x): | ||
| # self.val = x | ||
| # self.next = None | ||
|
|
||
| class Solution: | ||
| def hasCycle(self, head: Optional[ListNode]) -> bool: | ||
| visited_node = set() | ||
| current_node = head | ||
| if head is None: | ||
|
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. 自分なら、コーナーケースで early return する場合、関数の一番上に書くと思います。理由は、関数宣言と early return の間に書かれた内容を、 early return のロジックを読む間、読み手が短期記憶に保持し続けなければならないためです。これは短期記憶の要領の無駄遣いになり、読み手にとって不要な認知負荷になると思います。
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. ありがとうございます。納得しました。early returnの場合は関数の最初で書くように意識してみます。 |
||
| return False | ||
| while True: | ||
| if current_node.next is None: | ||
| return False | ||
| elif current_node.next in visited_node: | ||
| return True | ||
| else: | ||
| visited_node.add(current_node) | ||
| current_node = current_node.next | ||
| ``` | ||
| ## Step 2 | ||
| ### 読んだコード | ||
| - https://discord.com/channels/1084280443945353267/1195700948786491403/1195944696665604156 | ||
| - https://github.com/tk-hirom/Arai60/pull/1 | ||
| - https://github.com/katayude/yamaguchiLeetCode/pull/1 | ||
|
|
||
| ### 考えたこと | ||
| - Listのinの確認は、線形で舐めるのでできる限りsetで確認をしたい。 | ||
| - `while head`で最初のifの分岐をなくして可読性を上げられる可能性がある。 | ||
|
|
||
| ```python | ||
| # Definition for singly-linked list. | ||
| # class ListNode: | ||
| # def __init__(self, x): | ||
| # self.val = x | ||
| # self.next = None | ||
|
|
||
| class Solution: | ||
| def hasCycle(self, head: Optional[ListNode]) -> bool: | ||
| visited = set() | ||
| while 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. こちらのコメントをご参照ください。
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. ありがとうございます。納得しました。boolの評価はis Noneなどの形で行うように意識します。 |
||
| if head in visited: | ||
| return True | ||
| else: | ||
| visited.add(head) | ||
| head = head.next | ||
|
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. ありがとうございます。headが動くことに違和感があるという点に納得しました。連結リストを扱う際はheadは動かさず、別の変数に格納してから扱おうと思います。 |
||
| return False | ||
| ``` | ||
|
|
||
| ## Step 3(フロイドの循環検出法で書いてみる) | ||
| - fast, slowの2つのポインタを用意して、fastは2ノードずつ進む。slowは1ノードずつ進む。fastとslowが同じノードを指していたら、循環が存在する。 | ||
| - 利点はsetを用意しなくていいので空間計算量がO(1)になること | ||
| - 入力が空のケースをどう組み込むかを考えられず、一度間違ったコードを書いてしまった。(fastの初期値をhead.nextにしてしまった。)ポインタを動かしてから同じかどうかを評価すればいい。 | ||
| - fast.nextがNoneだとfast.next.nextにアクセスできないケースを考えず、`while fast`で評価してしまった。 | ||
| - 総じて考慮すべき条件が多いので、元のsetのやり方で書きたいと思った。(空間計算量O(n)が許されるなら。) | ||
|
|
||
| ```python | ||
| # Definition for singly-linked list. | ||
| # class ListNode: | ||
| # def __init__(self, x): | ||
| # self.val = x | ||
| # self.next = None | ||
|
|
||
| class Solution: | ||
| def hasCycle(self, head: Optional[ListNode]) -> bool: | ||
| fast = head | ||
| slow = head | ||
| while fast and fast.next: | ||
| fast = fast.next.next | ||
| slow = slow.next | ||
| if fast == slow: | ||
| return True | ||
| return False | ||
| ``` | ||
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.
current という単語に、あまり情報がないように思いました。単に node だけで十分だと思います。
current/previous/next と対比する場合には、付けても良いと思います。
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.
ありがとうございます!納得しました。形容詞を使う際は、対比するものがあるかどうかを意識して、対比先がなければ使わないようにしてみようと思います。