-
Notifications
You must be signed in to change notification settings - Fork 0
Create LinkedListCycle.md #1
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,109 @@ | ||
| # step1 何も見ずに解く | ||
| 問題文の説明を理解するのに時間を要す。 | ||
| 何のために`pos`という概念があるのか。 | ||
| とりあえず循環を検知するコードを書いて動かすことで、実装のためというよりテストケースの説明のための概念であることを理解する。 | ||
| この`pos`はpositionの略でしょうか? | ||
|
|
||
| ## 解答 | ||
| - 普通に書いたら書けたが、問題文を理解するのに時間がかかった。 | ||
| - 普段IDEに頼りきっているので、leetcode上のただのエディタで書くとメソッド名などまごついた。 | ||
| - contains()だっけ、has()だっけみたいな。 | ||
| - O(1)の解答方法は全く思いつかず。 | ||
| - 計算量 | ||
| - 時間計算量: O(n) | ||
| - 空間計算量: O(n) | ||
|
|
||
| ```java | ||
| /** | ||
| * Definition for singly-linked list. | ||
| * class ListNode { | ||
| * int val; | ||
| * ListNode next; | ||
| * ListNode(int x) { | ||
| * val = x; | ||
| * next = null; | ||
| * } | ||
| * } | ||
| */ | ||
| public class Solution { | ||
| public boolean hasCycle(ListNode head) { | ||
| if(head == null) return false; | ||
| // 巡回済みのnodeを保持するSet | ||
| HashSet<ListNode> nodeSet = new HashSet<>(); | ||
| ListNode checkNode = head; | ||
| while (checkNode.next != null) { | ||
| if (nodeSet.contains(checkNode)) return true; | ||
| nodeSet.add(checkNode); | ||
| checkNode = checkNode.next; | ||
| } | ||
| return false; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| # step2 他の方の解答を見る | ||
| フロイドの循環検出法を知る。 循環小数の検出などにも使用するよう。 | ||
| 速度違いで2つのポインタを動かすことで、ループがあればいつか必ず追いつくということか。 | ||
|
|
||
| ## 解答 | ||
| - leetcodeの画面で動かすと、フロイド法は0ms、Set使用時は4msとなる。 | ||
| - 時間計算量は同じO(n)なのにここまで差がつくのが直感に反した。 | ||
|
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. ありがとうございます。 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 の実行時間はブレがあるので、あまり信用しないほうがよさそうです。
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. 当初気づかなかったのですが、同じプログラムでもleetcodeの実行時間ブレますね。 |
||
| - Setを使った場合、Hashの計算やメモリの割り当てなどで余計に時間がかかるからだろうか? | ||
| - 計算量 | ||
| - 時間計算量: O(n) | ||
| - 空間計算量: O(1) | ||
|
|
||
| ```java | ||
| public class Solution { | ||
| public boolean hasCycle(ListNode head) { | ||
| if(head == null) return false; | ||
| ListNode fast = head; | ||
| ListNode slow = head; | ||
| while (fast != null && fast.next != null) { | ||
| fast = fast.next.next; | ||
| slow = slow.next; | ||
| if (fast == slow) return true; | ||
| } | ||
| return false; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## 解答2 | ||
| - Setを使った解法についてもstep1の変数名を少し改良して再実装 | ||
|
|
||
| ```java | ||
| public class Solution { | ||
| public boolean hasCycle(ListNode head) { | ||
| if (head == null) return false; | ||
|
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. 確かに後続の実装と意味的に分かれてるので改行入れた方が親切ですね。 |
||
| HashSet<ListNode> visited = new HashSet<>(); | ||
| ListNode node = head; | ||
| while (node.next != null) { | ||
| if (visited.contains(node)) return true; | ||
| visited.add(node); | ||
| node = node.next; | ||
| } | ||
| return false; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## step3 3回ミスなく書く | ||
| 何回か書いたのでスラスラかける。 | ||
| 所要時間 2分程度 | ||
| ## 解答 | ||
| ```java | ||
| public class Solution { | ||
| public boolean hasCycle(ListNode head) { | ||
| if (head == null) return false; | ||
|
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 構築コストが必ずかかるようになるので、つけておいてもいいでしょう。
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. 個人的にはこのようなgurad節的なものを書きたくなります。 確かに毎回{}で囲う方が事故は確実に少なくなりますね。 |
||
| HashSet<ListNode> visited = new HashSet<>(); | ||
|
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. やっぱりそちらの方が親切ですね。 Javaのメソッドや変数名はlowerCamelCaseであってます! 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. これも好みかもしれませんが、僕も kt-from-j さんと同様に型からわかることは書かないですね。 |
||
| ListNode node = head; | ||
| while (node != null && node.next != null) { | ||
|
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.next のチェックっていります? いや、してはだめということはないですが。
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. フロイドの循環検出法で書いた時のことが頭の片隅にあり、なんとなくで書いてしまっていたものと思います。
このチェックがある場合、ラスト1回のループが不要になるため完全に無意味ではないから駄目ではないということでしょうか。 |
||
| if (visited.contains(node)) return true; | ||
| visited.add(node); | ||
| node = node.next; | ||
| } | ||
| 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.
そうだと思います(私もこの問題に関係無いposが出てきて少し混乱した記憶があります)
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の問題や変数の名付けなどに戸惑ってしまいました。