一,问题描述
1,一个单链表,判断内部有没有循环;
2,如果有循环,求出这个循环的长度;
3,如果有循环,找到这个循环的第一个点(和解除环是一个问题);
二、问题分析
1,方法一:这道题目最容易想到的是暴力求解法,复杂度O(n^2)。使用两个指针a, b。a从表头开始一步一步往前走,遇到null则说明没有环,返回false;a每走一步,b从头开始走,如果遇到b==a.next,则说明有环true,如果遇到b==a,则说明暂时没有环,继续循环。下面会用这种方法实现问题3。
2,方法二:用数学求解出关系(关系如下图):
使用两个指针slow,fast。两个指针都从表头开始走,slow每次走一步,fast每次走两步,如果fast遇到null,则说明没有环,返回false;如果slow==fast,说明有环,并且此时fast超了slow一圈,返回true。
为什么有环的情况下二者一定会相遇呢?因为fast先进入环,在slow进入之后,如果把slow看作在前面,fast在后面每次循环都向slow靠近1,所以一定会相遇,而不会出现fast直接跳过slow的情况。
三、java代码
1,暴力求解问题三:
public static ListNode detectCycle(ListNode head) {
if(head == null) {
return null;
}
ListNode fast = head.next;
ListNode slow = head;
while(fast != null) {
slow = head;
while(slow != fast) {
if(slow == fast.next)
return slow;
slow = slow.next;
}
fast = fast.next;
}
return null;
}
2,数学求解问题三:
public static ListNode detectCycle2(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while(fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if(slow == fast)
break;
}
if(fast == null || fast.next == null ) {
return null;
}else {
slow = head;
while(slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
3,求解问题1,2:只需要在求解问题三中记录走过的数量就可以了。