题目描述
对于一个给定的链表,返回环的入口节点,如果没有环,返回null。
步骤:
<1> 定义两个指针p1和p2,在初始化时都指向链表的头节点。
<2> 如果链表中的环有n个节点,指针p1先在链表上向前移动n步。
<3> 然后指针p1和p2以相同的速度在链表上向前移动直到它们相遇。
<4> 它们相遇的节点就是环的入口节点。
那么如何得到环中的节点数目?即通过一快一慢两个指针来解决这个问题。当两个指针相遇时,表明链表中存在环。两个指针相遇的节点一定是在环中。可以从这个节点出发,一边继续向前移动一边计数,当再次回到这个节点时,即可得到环中的节点数了。
public class TestIsCircleList {
public static void main(String[] args) {
TestIsCircleList t = new TestIsCircleList();
ListNode a = new ListNode(1);
ListNode b = new ListNode(2);
ListNode c = new ListNode(3);
ListNode d = new ListNode(4);
ListNode e = new ListNode(5);
ListNode f = new ListNode(6);
ListNode g = new ListNode(7);
a.next = b;
b.next = c;
c.next = d;
d.next = e;
e.next = f;
f.next = g;
g.next = d; // 形成环状
//boolean isHave = t.hasCycle(a);
//System.out.println(isHave);
detectCycle(a);
}
public static ListNode detectCycle(ListNode head) {
ListNode slow = head; // 慢指针
ListNode fast = head; // 快指针
boolean isHaveCirle = false;
while(null != fast && null != fast.next){
slow = slow.next;
fast = fast.next.next;
if(slow == fast){
// 通过一快一慢两个指针来解决这个问题。当两个指针相遇时,表明链表中存在环
System.out.println("链表有环");
isHaveCirle = true;
break;
}
}
if(!isHaveCirle){
return null;
}
int circleCount = 1;
slow = slow.next;
// 求环的节点数
while(fast != slow){
circleCount++;
// 一继续向前移动一边计数,当再次回到这个节点时,即可得到环中的节点数了
slow = slow.next;
}
ListNode pre = head;
ListNode post = head;
for(int i=0;i<circleCount;i++){
post = post.next;
}
while(pre != post){
pre = pre.next;
post = post.next;
}
return pre;
}
}