循環リンクリスト
質問:
リンク リストのヘッド ノード head が与えられた場合、リンク リストにリングがあるかどうかを判断してください。
リンクされたリスト内に次のポインタを継続的に追跡することによって再度到達できるノードがある場合、リンクされたリスト内にサイクルが存在します。指定されたリンク リスト内のリングを表すために、評価システムは内部で整数 pos を使用して、リンク リストの末尾がリンク リストに接続される位置を示します (インデックスは 0 から始まります)。注: pos はパラメータとして渡されません。リンクリストの実態を特定するためだけに。
リンクされたリストに循環がある場合は true を返します。それ以外の場合は false を返します。
出典: LeetCode循環リンク
リスト アイデア 1: 暴力的な解決策
リンク リストを最初から走査し、ノードを走査するたびに、そのノードが最初からすでに出現しているかどうかを確認します。これは私たちが考えることができる最初の強引な解決策です。時間計算量 O(N^2) 空間計算量 O(1)。
アイデア 2: 高速ポインターと低速ポインター
低速と高速の 2 つのポインターを作成し、それらが同時にヘッド ノードを指すようにします。低速は一度に 1 ステップ、高速は一度に 2 ステップを実行します。ループの最終結果がslow=fastの場合、リンク・リストはリングですが、fast=nullptrの場合、リンク・リストはリングではありません。
理由は二人で走るのと同じで、コースは円形で走り続けるので、同じスタートラインから走り始めると速い人は遅い人に必ず追いつきます。
コード:
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode* slow=head;
ListNode* fast=head;
while(slow && fast && fast->next)
{
slow=slow->next;
fast=fast->next->next;
if(slow==fast)
{
return true;
}
}
return false;
}
};
エラーが発生しやすいポイント:
リンクリスト内のリングのエントリノード
質問:
リンク リストが与えられた場合、リンク リストがリングに入り始める最初のノードを返します。リンクされたリストのヘッド ノードから開始してリングへの次のポインタをたどると、最初のノードがリングのエントリ ノードになります。リンクされたリストが非巡回の場合は null を返します。
特定のリスト内のサイクルを表すには、整数 pos を使用して、リストの末尾が結合するリスト内の位置を示します (インデックスは 0 から始まります)。pos が -1 の場合、リストにはサイクルがありません。pos はリングを識別するためにのみ使用され、関数にパラメーターとして渡されないことに注意してください。
説明: 指定されたリンク リストの変更は許可されていません。
出典: LeetCodeリンク リストのリングのエントリ ノード
アイデア:
まずリンク リストにリングがあることを証明し、次にエントリ ノードを見つけます。リングがある場合、私たちはゆっくりと歩いており、速歩で移動した距離の半分を歩いている必要があります。次の図の分析を見てください。
コード:
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* slow=head;
ListNode* fast=head;
while(slow && fast && fast->next)
{
slow=slow->next;
fast=fast->next->next;
if(slow==fast)
{
break;
}
}
if(fast==nullptr || fast->next==nullptr)
{
return nullptr;
}
slow=head;
while(slow!=fast)
{
slow=slow->next;
fast=fast->next;
}
return fast;
}
};