题意描述:给定一个单向链表,(1)判断其是否有环;(2)如果有环找出环结点。
解题分析:一个单向链表如果有环,则必然存在最后一个结点的next指针指向链表中其他任意一个结点。如果单从结点上判断,这就相当于一没有尽头的死循环,所以一个指针肯定不行,就想到利用两个指针,然后以不同的速度从起点出发,如果两个指针能够相遇,则说明存在回路(证明就是小时常做的应用题目:小明和小红在操场跑步一个快一个慢,从一次相遇到下一次相遇问题、时针分针相遇问题。。。这里不再证明)。所在判断是否有环的代码如下:
public class LinkedListCycle {//链表结构
int val;
LinkedListCycle next;
LinkedListCycle(int x){
val = x;
next = null;
}
}
boolean hasCycle(LinkedListCycle head){
LinkedListCycle p,q;
p = head;//从头开始遍历
q = head;//从头开始遍历
while(q != null && q.next != null){
p = p.next;//一次前进一步
q = q.next.next;//一次前进两步
if(q == p)//如果相遇则返回true
return true;
}
return false;
}
在上面的基础上该如何找出环结点呢?
如图所示,第一次相遇是在K结点(相对于环结点),此时指针P走了S1=[X+K+m(K+Y)]步(表示慢赶到K后又指针转了m圈与快指针在K相遇),指针Q走了S2=[X+n(K+Y)+K]步(表示快指针转了n圈后又走了K步与慢指针在K相遇)。由于S2=2*S1,解得:(n-2m)(K+Y) = X+K,(n-2m)为一个常数项,X=(n-2m-1)(Y+K)+Y。所以一个指针从K出发,另一个指针从头出发,再次相遇点就是环结点:
LinkedListCycle detectCycle(LinkedListCycle head){
LinkedListCycle p,q;
p = head;
q = head;
while(q != null && q.next != null){
p = p.next;
q = q.next.next;
if(p == q)//第一次相遇
break;
}
if(q==null || q.next==null)
return null;
p = head;
while(p != q){
p = p.next;
q = q.next;
}
return q;
}
这样的题目都是有套路的,如果曾经做过,记住结论就好了,但真正应当做到理解解题原理,能够举一反三!!!