タイトル説明
リンクリストの場合、リングが含まれている場合は、リンクリストのリングのエントリノードを見つけてください。それ以外の場合は、nullを出力します。
アイデア分析
この方法は私たち自身のものではありませんが、解決策は確かに非常に賢いので、この方法はブログのコンテンツとして使用されます。
元のメソッドアドレス:https://blog.nowcoder.net/n/deaa284f105e48f49f38b5d7cb809cd7?f = comment
アイデアの説明:
リンクリストの構造が次のようになっているとします。
- まず、それがリングであるかどうかを判別します。fasthとslwoの2つのポインターを設定します。高速は一度に2つのステップを実行し、低速は一度に1つのステップを実行します。Fastは間違いなくSlowよりも早くリングに入ります。多くのサイクルの後、最終的にSlowと出会う場合(遭遇がポイントPであると仮定)、Fastが円の中にあり、リングがあることを意味します。
このプロセスではslow走过的距离是a+b
、fast走过的距离是:a+nb+(n-1)c
。(ここでn回bとn-1回cの理由は、最終的に点Pで出会ったため、移動距離が1少ないcと高速で言われたためです)
したがって、速度の関係は次のようになります。2(a + b)= a + nb +(n-1)c等式関係により、n = 2であることがわかります。そして、a = cを取得します。- その後、リング入口の判定を行います。
スロー2をpHeadから入るように設定すると、スローはそれが出会うポイントqから開始します。a = cであるため、slow2がslowと出会うと、それがループのエントリポイントになります。
コード
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead)
{
if(pHead == null || pHead.next ==null) return null;
ListNode fast = pHead;
ListNode slow = pHead;
while(fast!=null||fast.next!=null){
//由于如果存在环,就会一直循环下去,如果不存在环,就会在满足要求后跳出循环,返回一个null
fast = fast.next.next;//快指针一次走两步
slow = slow.next;//慢指针一次走一步
if(fast==slow){
//当快慢指针相遇
ListNode slow2 = pHead;
while(slow2!=slow){
slow2 = slow2.next;//slow2指针从phead出进入一次走一步当与slow相遇即为环入口
slow = slow.next;
}
return slow2;
}
}
return null;
}
}