循環リンクリストの簡単な判断
循環リンクリストII(ループノードの検索)
リンクリストを指定して、リンクリストがループに入り始める最初のノードを返します。リンクリストにリングがない場合は、nullが返されます。
1つ、ハッシュ
リンクリスト内の各ノードをトラバースして記録します。以前にトラバースされたノードに遭遇すると、リンクリスト内にリングがあると判断できます。ハッシュテーブルを使用して簡単に実装できます。
class Solution {
public:
ListNode* detectCycle(ListNode* head)
{
unordered_set<ListNode*> visited;
while (head != NULL)
{
if (visited.count(head))
{
return head;
}
visited.insert(head);
head = head->next;
}
return NULL;
}
};
ダブルポインタ
アルゴリズムフロー:
高速ポインタと低速ポインタの2つのポインタを設定します。
最初の結果:ファストはリンクリストの最後を通過し、リンクリストにループがないことを示し、NULLを直接返します
2番目の結果は、両手がリングで初めて出会うことです。ステップ間の関係を分析してみましょう。
リンクリストにx + yノードがあるとします。その中には、リンクリストの先頭からリンクリストのエントリまでのxノードがあり(リンクリストのエントリノードは数えません)、リンクリストのリングにはyノードがあります。2つのポインタがステップfとsはそれぞれ、次のようになります。
f = 2s(高速ポインターの各ラウンドが低速ポインターよりも1ステップ多いため)
f = s + ny(両方のポインターがxステップを通過し、一致するまでリング内を一周します。オーバーラップすると、高速ポインターは低速ポインターよりもリング長の整数倍だけ移動します。これはnと見なされます。 )
2つの式、f = 2ny、s = nyを引くことにより、つまり、fとsはなくなり、2n、n個のリングの周囲長になります。
このとき、高速ポインタはヘッドノードを指すようにリセットされ、sポインタとfポインタは各ラウンドで1ステップ進みます。
f = 0、s = ny
f = x、s = ny + xの場合、2つのポインターは一致し、リンクリストリングのエントリを同時に指します。
class Solution {
public:
ListNode* detectCycle(ListNode* head)
{
ListNode* slow = head, * fast = head;
while (fast != NULL && fast->next != NULL)
{
slow = slow->next;
fast = fast->next->next;
if (fast == slow)
break;
}
if (fast == NULL || fast->next == NULL) return NULL;
ListNode* ptr = head;
while (ptr != slow)
{
ptr = ptr->next;
slow = slow->next;
}
return ptr;
}
};