【题目描述】
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
实例1:有链表3-->2-->0-->-4-->2,可以一眼看出其内部是有环的。
但是用代码如何判断有环? 如何找到开始入环的第一个节点?
【第一步判断有环】
因为有环的存在,链表像是两个人围绕着操场顺时针跑步。什么时候两个人能遇见当然是一个人速度大于另一个人的速度。
因此我们定义两个指针,一个fast指针每次移动两个节点,一个slow指针每次移动一个节点,当两个节点相遇时候就能够说明链表是有环的了。
public static ListNode detectCycle(ListNode head) {
// 定义快慢指针,快指针每次走两步,慢指针每次走一步
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next;
fast = fast.next;
// 说明有环
if (slow == fast) {
// 找到入环的第一个节点
}
}
return null;
}
【找到入环的第一个节点】
设,从起始点到换入口点的距离是x,入口点到相遇的距离是y,相遇到出口点距离为z
slow节点走过的距离为x+y,fast节点走过的距离为x+y+n(y+z),其中n(y+z)表示fast在其中转了很多圈了然后才相遇
那么就有 (x + y )*2 = x+y+n(y+z)
得x = (n-1)*y +n*z
【表明】如果再有一个指针index 从head处出发,fast从相遇位置出发,他们每次都走一步,则相遇的位置就是入口节点。
【完整代码】
package link;
public class DetectCycle {
public static void main(String[] args) {
ListNode node1 = new ListNode(3);
ListNode node2 = new ListNode(2);
ListNode node3 = new ListNode(0);
ListNode node4 = new ListNode(4);
node1.next = node2;
node2.next = node3;
node3.next = node4;
// 形成环状
node4.next = node2;
ListNode node = detectCycle(node1);
System.out.println("环的入口:" + node);
}
public static ListNode detectCycle(ListNode head) {
if (head == null) {
return null;
}
// 定义快慢指针,快指针每次走两步,慢指针每次走一步
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next;
fast = fast.next;
// 说明有环
if (slow == fast) {
ListNode index1 = fast;
ListNode index2 = head;
while (index1 != index2) {
index1 = index1.next;
index2 = index2.next;
}
return index2;
}
}
return null;
}
}