141. リンクリストサイクル
リンク リストの先頭であるhead を指定すると、リンク リストに循環があるかどうかが判断されます。
次のポインタを継続的にたどることによって再び到達できるノードがリスト内にある場合、リンクされたリスト内にサイクルが存在します。内部的には、pos は、tail の次のポインタが接続されているノードのインデックスを示すために使用されます。pos はパラメータとして渡されないことに注意してください。
リンクされたリストに循環がある場合は trueを返します。それ以外の場合はfalse を返します。
例 1:
入力: head = [3,2,0,-4]、pos = 1
出力: true
説明:リンクされたリストにサイクルがあり、末尾が最初のノード (0 から始まる) に接続されています。
例 2:
入力: head = [1,2]、pos = 0
出力: true
説明:リンクされたリストにサイクルがあり、末尾が 0 番目のノードに接続されています。
例 3:
入力: head = [1]、pos = -1
出力: false
説明:リンクされたリストに循環がありません。
制約:
- リスト内のノードの数は[ 0 , 1 0 4 ] [0, 10^4] の範囲内です。[ 0 ,1 04 ]。
- − 1 0 5 < = ノード。val < = 1 0 5 -10^5 <= Node.val <= 10^5− 1 05<=ノード。_ _ _ v a l<=1 05
- pos は -1 またはリンク リスト内の有効なインデックスです。
From: LeetCode
Link: 141. リンクされたリストのサイクル
解決:
アイデア:
基本的な考え方:
円形のトラックを走る 2 人のランナーを想像してください。一方のランナー (ウサギ) の方が、もう一方のランナー (カメ) よりもはるかに速いです。同じ位置からスタートして同じ方向に走った場合、速いランナー (ウサギ) が最終的に遅いランナー (カメ) を追い越します。同様に、リンクされたリストにサイクルがある場合、サイクル内でより高速なポインタが最終的により低速なポインタと出会うことになります。
コードの説明:
1. 初期化:
- カメ (動きの遅い) とウサギ (動きの速い) の 2 つのポインターがあります。どちらもリンクされたリストの先頭から始まります。
2. 動き:
- カメは一度に 1 歩ずつ進みます (カメ = カメ→次)。
- ウサギは一度に 2 歩ずつ移動します (ウサギ = ウサギ→次→次)。
3. サイクルの確認:
- リンクされたリストにサイクルがない場合、ウサギ (より速く移動する) は最終的にリストの最後に到達し、NULL ポインターに遭遇します。
- サイクルがある場合、ウサギは最終的にカメを「ラップ」し、サイクル内のどこかの時点で出会います。
4. ループの終了:
- hare と hare->next が NULL でない限り、ループは継続します。
- カメとウサギのポインタが一致する場合 (カメ == ウサギ)、それはサイクルの存在を示し、関数は true を返します。
- ポインタが一致しないままループが終了した場合、サイクルは存在せず、関数は false を返します。
コード:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool hasCycle(struct ListNode *head) {
if (!head) return false; // If list is empty
struct ListNode *tortoise = head; // Slow pointer
struct ListNode *hare = head; // Fast pointer
while (hare != NULL && hare->next != NULL) {
tortoise = tortoise->next; // Move slow pointer one step
hare = hare->next->next; // Move fast pointer two steps
if (tortoise == hare) return true; // If they meet, there's a cycle
}
return false; // If loop exits, there's no cycle
}