一:判断是否有环
思路:使用快慢引用法解决 是否有环
假设链表是一个有环链表,且由f指向c构成环。那么 使用两个指针 A 和 B,让两指针同时向后遍历 而且B的遍历速度是A的两倍,呢么如果是有环的话,B终究会追上A。因此我们可以 以AB是否相遇作为判断是否有环的必要条件。
下面是图例:
最终BA在e相遇,于是可以得出 此链表有环。
代码:
public Entry<E> isLoop(){
Entry<E> fast = first , slow = first;//定义两个指针,分别是快和慢
//遍历一遍链表,如果最后是null的话就代表没有环
while (fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
//如果俩相遇了,代表有环
if (fast == slow){
return fast;
}
}
return null;
}
二:求出成环的位置
思路:s=vt(路程=速度*时间)用方程思想列等式解
因为路程知道,速度知道(二倍关系),时间也知道(相等),所以可以列等式求关系。再用代码体现出关系,就可以解决这道题了。
如图:假设链表是Link fast是快的那个指针,Slow是慢的呢个指针,蓝色是fast走过的路程,绿色是slow走过的路程
K是环的入口,P是快慢指针相遇的地方
a,b,c 分别代表三段长度。
所以图就可以变成:
然后,让指针从 相遇点p 和起始点 同时遍历,这样由于 c = a 所以p和first在k相遇,而k就是入口点。
public Entry<E> getIntersectEntry(){
Entry<E> meet = isLoop();
if(meet == null){
return null;
}
Entry<E> p = meet;
Entry<E> q = first;
while (p!=q){
p = p.next;
q = q.next;
}
return p;
}