タイトル説明:
リンクリストの場合、リングが含まれている場合は、リンクリストのリングのエントリノードを見つけてください。それ以外の場合は、nullを出力します。
問題解決のアイデア:
高速および低速ポインターソリューション:この問題には、高速ポインターと低速ポインターの2つのポインターソリューションを使用できます。
高速ポインタは一度に2つの要素を実行し、低速ポインタは一度に1つずつ実行します。円があれば、ある日、速いポインターが遅いポインターに追いつくことができるようになります。
次の図に示すように、最初に高速ポインタと低速ポインタが出会うポイントpを見つけます。さらに、リングの入口が点qにあり、ヘッドノードから点qまでの距離がA、2点間の距離qpがB、2点間の距離pqがCであると仮定します。
高速ポインタは低速ポインタの2倍の速度であり、それらは点pで交わるため、式2(A + B)= A + B + C + Bを得ることができます(リングの前のリンクリストが非常に長く、リングが短い場合、高速ポインターは、リングに入った後(n回転すると仮定)、低速ポインターに到達する前に数回回転する場合があります。ただし、いずれの場合も、低速ポインターは、最初の円に入るときに高速に遭遇します。 2(A + B)= A + nB +(n-1)C)3の式から、C = Aであることがわかります。
この時点で、スローポインターはすでにpにあるため、新しいポインターslow2を作成し、ヘッドノードから開始して、毎回次のポインターにのみ移動することができます。元のスローポインターは引き続き元のポインターを保持します。方法、slow2と同じです。一度に次の1つだけに行きます。
A = Cであることがわかっているので、slow2と元のslowポインターが出会うのを楽しみにしています。したがって、それらが出会うときはqでなければなりません。
リングの開始点qである現時点で同じノードを指しているため、slow2またはslowのいずれかに戻ることができます。
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead) {
ListNode fast = pHead;
ListNode slow = pHead;
while(fast != null && fast.next != null ) {
fast = fast.next.next;
slow = slow.next;
if(slow == fast) {
ListNode slow2 = pHead;
while(slow != slow2) {
slow2 = slow2.next;
slow = slow.next;
}
return slow;
}
}
return null;
}
}