给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
第一种解法: 利用set存储每个结点,如果出现过则返回该结点,如果遍历完了都没找到则返回null
第二种解法: 双指针法: 定义两个指针,一个一次走两步的快指针一个慢指针,如果有环存在,则他们一定会在环上某个结点相遇.这时候他们都开始每次都一步,则下次相遇的点一定是环入口结点.
1、设置快慢指针,假如有环,他们最后一定相遇。
2、两个指针分别从链表头和相遇点继续出发,每次走一步,最后一定相遇与环入口。 思路2证明如下 证明结论1:设置快慢指针fast和low,fast每次走两步,low每次走一步。假如有环,两者一定会相遇(因为low一旦进环,可看作fast在后面追赶low的过程,每次两者都接近一步,最后一定能追上)。
代码:
public ListNode EntryNodeOfLoop(ListNode pHead)
{
//找出环中相遇的点
ListNode p1=pHead; //每次走一步的结点
ListNode p2=pHead;//每次走两步的结点
ListNode pmeet=null;
while (p2!=null&&p2.next!=null){ //p2比p1跑的快,如果没有环的话p2先挂掉,所以只判断p2就可以了
p1=p1.next;
p2=p2.next.next;
if (p1==p2){
pmeet=p1;
break;
}
}
if (pmeet==null){//没环,没有相遇
return null;
}
//如果有环.p1从头走,p2从相遇结点走,下一次相遇就是那个环结点.
p1=pHead;
p2=pmeet;
while (p1!=p2){
p1=p1.next;
p2=p2.next;
}
return p1;
}