Skip to content

Commit 0ba0550

Browse files
authored
Merge pull request #18 from colorbox/142
142. Linked List Cycle II
2 parents 37d007f + 95b2bdd commit 0ba0550

File tree

6 files changed

+200
-0
lines changed

6 files changed

+200
-0
lines changed

142/step1.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
所要時間 31:00
3+
Time: O(NlogN)
4+
Space: O(N)
5+
6+
mapを使う解法自体は考慮できていたが、構文ミスでハマった。
7+
これまで訪れたノードを記憶しておき、再訪したノードがあればそれを返すことでサイクルのループ開始ノードを返せる。
8+
9+
*/
10+
class Solution {
11+
public:
12+
ListNode *detectCycle(ListNode *head) {
13+
if (!head) {
14+
return nullptr;
15+
}
16+
17+
map<ListNode*, bool> visited;
18+
ListNode* current = head;
19+
while (current) {
20+
if (visited[current]) {
21+
return current;
22+
}
23+
visited[current] = true;
24+
current = current->next;
25+
}
26+
27+
return nullptr;
28+
}
29+
};

142/step2.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
所要時間 8:01
3+
Time: O(n)
4+
Space: O(1)
5+
解説や他の人のコードを読んでFloydアルゴリズムで実装。
6+
サイクルがあh字丸までの距離、1サイクル分の距離、サイクル開始からfast,slowが出会うまでの距離、fast/slowが出会うまでの進行距離を考慮すると
7+
fast/slowが出会った場所からサイクルの開始までの距離と
8+
リストの先頭からサイクルの開始までの距離が等しいことが分かるため、それを求めた。
9+
*/
10+
class Solution {
11+
public:
12+
ListNode *detectCycle(ListNode *head) {
13+
if (!head) {
14+
return nullptr;
15+
}
16+
ListNode* slow = head->next;
17+
if (!slow) {
18+
return nullptr;
19+
}
20+
21+
ListNode* fast = head->next->next;
22+
if (!fast) {
23+
return nullptr;
24+
}
25+
26+
while (slow != fast) {
27+
slow = slow->next;
28+
if (!fast || !fast->next) {
29+
return nullptr;
30+
}
31+
32+
fast = fast->next->next;
33+
}
34+
35+
ListNode *current = head;
36+
while (slow != current) {
37+
slow = slow->next;
38+
current = current->next;
39+
}
40+
41+
return current;
42+
}
43+
};

142/step3_froyd.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
fast && fast->next
3+
という記法がその場で出てこなかった
4+
if (fast != slow)
5+
という記法にこだわってしまったため
6+
終了条件がslow==fastだったのでそれをそのままループの継続条件にしてしまった
7+
8+
基本的にリスト内にcycleがなければよい( = もしあればその場でreturn nullptrできる)
9+
ので(fast != slow)というのは実はループを回すうえでは重要ではない
10+
なので、先行するfastがnullとならないことさえ確認できればよい
11+
この書き方に固執してしまうとslowとfastの初期化が面倒になり、それに伴って本来不要な早期returnが必要となってしまう
12+
fast == slowはループの終了条件として使うほうが無駄を減らせて自然なコードになる。
13+
*/
14+
class Solution {
15+
public:
16+
ListNode *detectCycle(ListNode *head) {
17+
ListNode* slow = head;
18+
ListNode* fast = head;
19+
20+
while (fast && fast->next) {
21+
slow = slow->next;
22+
fast = fast->next->next;
23+
24+
if (slow == fast) {
25+
break;
26+
}
27+
}
28+
29+
if (!fast || !fast->next) {
30+
return nullptr;
31+
}
32+
33+
ListNode* from_head = head;
34+
while (slow != from_head) {
35+
slow = slow->next;
36+
from_head = from_head->next;
37+
}
38+
39+
return from_head;
40+
}
41+
};

142/step3_set.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
mapではなくsetを使い、存在確認にcontainsを使用するよに修正。
3+
*/
4+
class Solution {
5+
public:
6+
ListNode *detectCycle(ListNode *head) {
7+
set<ListNode*> visited;
8+
ListNode* current = head;
9+
10+
while (current) {
11+
if (visited.contains(current)) {
12+
return current;
13+
}
14+
15+
visited.insert(current);
16+
current = current->next;
17+
}
18+
19+
return nullptr;
20+
}
21+
};

142/step4_floyd.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
step3_floydにてwhileの条件にしていた`(fast && fast->next)`とその直後の`(!fast || !fast->next)`は反転しているだけで実質同じという指摘を受けて書き直す。
3+
Pythonのようにwhileに対してelseをつけられないので、while(true)のループの中でif-elseで分岐させる。
4+
while(true)の中で分岐させると、ネストが深くなってしまい個人的に避けている書き方だったが、こちらのほうがifが少なくできて読みやすい
5+
6+
*/
7+
class Solution {
8+
public:
9+
ListNode *detectCycle(ListNode *head) {
10+
ListNode* slow = head;
11+
ListNode* fast = head;
12+
13+
while (true) {
14+
if (fast && fast->next) {
15+
slow = slow->next;
16+
fast = fast->next->next;
17+
if (slow == fast) {
18+
break;
19+
}
20+
} else {
21+
return nullptr;
22+
}
23+
}
24+
25+
ListNode* from_head = head;
26+
while (slow != from_head) {
27+
slow = slow->next;
28+
from_head = from_head->next;
29+
}
30+
return from_head;
31+
}
32+
};

142/step5_floyd.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
https://discord.com/channels/1084280443945353267/1192728121644945439/1194203372115464272
3+
を参考にstep4_floydを書き直した
4+
>「機械の使い方の説明です。まず、青いランプが5つついていることを確認してください。ランプがついていなかった場合は、直ちに使用を中止して事務所に連絡してください。…長い使い方の説明…。」
5+
>のほうが素直ですよね。
6+
という説明がしっくりきた
7+
早期returnをしたほうが考えること減ってわかりやすくなる。
8+
`while(fast && fast->next)`という書き方にこだわってしまっていたので、step4時点でこれが見えてなかった。
9+
*/
10+
class Solution {
11+
public:
12+
ListNode *detectCycle(ListNode *head) {
13+
ListNode* slow = head;
14+
ListNode* fast = head;
15+
16+
while (true) {
17+
if (!fast || !fast->next) {
18+
return nullptr;
19+
}
20+
slow = slow->next;
21+
fast = fast->next->next;
22+
if (slow == fast) {
23+
break;
24+
}
25+
}
26+
27+
ListNode* from_head = head;
28+
while (slow != from_head) {
29+
slow = slow->next;
30+
from_head = from_head->next;
31+
}
32+
return from_head;
33+
}
34+
};

0 commit comments

Comments
 (0)