1、判断链表中是否存在环
快慢指针,追及问题,若链表中存在环,快指针必定会在环中追上慢指针
public static boolean isCycle(Node header) {
if (header == null) {
return false;
}
Node fast = header;
Node slow = header;
// 快指针不为空,慢指针必不为空
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) return true;
}
return false;
}
2、若存在环,求环的长度
快指针的速度是慢指针的2倍,当两指针第二次在环中相遇时,快指针比慢指针多走的部分即是环的长度
public static int getCycleLength(Node header) {
if (header == null) {
return 0;
}
Node fast = header;
Node slow = header;
int res = 0;
// 快指针不为空,慢指针必不为空
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
// 第一次相遇点
if (fast == slow) {
// fast的速度是slow的2倍,再次相遇比slow多走了一圈
do {
slow = slow.next;
fast = fast.next.next;
// fast比slow多走一步
res++;
} while (slow != fast); // 直到第二次相遇
return res;
}
}
return res;
}
3、若存在环,求环的入口
如图,第一次相遇时候,慢指针走过的路径是
S
=
l
1
+
l
2
S=l_1+l_2
S=l1+l2
快指针走过的路径是(n为快指针比慢指针多走的圈数)
F
=
l
1
+
l
2
+
n
(
l
2
+
l
3
)
F = l_1 +l_2+ n(l_2+l_3)
F=l1+l2+n(l2+l3)
因为快指针速度是慢指针的2倍,所以
2
(
l
1
+
l
2
)
=
l
1
+
l
2
+
n
(
l
2
+
l
3
)
2(l_1+l_2)=l_1 +l_2+ n(l_2+l_3)
2(l1+l2)=l1+l2+n(l2+l3)
最终得:
l
1
=
(
n
−
1
)
(
l
2
+
l
3
)
+
l
3
l_1=(n-1)(l_2+l_3)+l3
l1=(n−1)(l2+l3)+l3
当n=1时,L1=L3,所以,当两指针第一次相遇时,只需将其中一个指针重置到链表起点,然后两指针每次后移一个节点,再次相遇的地方就是环的入口点了
public static Node getCycleEntryNode(Node header) {
if (header == null) {
return null;
}
Node fast = header;
Node slow = header;
// 快指针不为空,慢指针必不为空
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
// 指针第一次相遇点
if (slow == fast) {
// 将其中一个指针回到起点
slow = header;
// 指针每次向后移动一步,再次相遇点就是环的入口点
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
return null;
}