题目
这个主要分为两个题目分别是:
- 判断是否有环
- 寻找环的入口
判断是否有环:
寻找环的入口:
解题
判断是否有环:
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if(slow.equals(fast)){
return true;
}
}
return false;
}
}
寻找环的入口:
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if(slow.equals(fast)){
ListNode startNode = head;
while(!startNode.equals(slow)){
startNode = startNode.next;
slow = slow.next;
}
return startNode;
}
}
return null;
}
}
思路
其实这两道题是相关联的,首先是判断是否有环,然后在有环的基础上去寻找换的入口,所以我们接下里就循循渐进。
首先我们来思考一下怎么样才能判断是否有环呢?
这里我们可以想到用快慢指针:
- 如果一个链表没有环,那么快指针走的永远是比慢指针走的快的,相差的距离也是越来越远的,这样永远是不可能相遇的,
- 如果一个链表中有环的话,那么当快指针进入到环中之后就一直转圈,那么慢指针就可以慢慢追,那么他们俩就会相遇。
所以第一题很简单我们就让两个指针一直走,然后如果两个人能够相遇就是有环,不能相遇走到了null
那就是没有环。
第二题寻找一个环的出口,这应该怎么找呢?
接下来画个图寻找一下规律:
这里我们就先假设相遇的点是P点,然后这时直线的距离是X,入口到P是y,P到入口是Z,
然后我们可以进行推导一下:
慢指针走过的距离: x+y
快指针走过的距离: x+n(y+z)+y (因为快指针有可能在环里走了很多圈)
快指针走过的距离是慢指针距离的两倍:
2(x+y) = x+n(y+z)+y
化简: x = (n-1)(y+z)+z
这时候令n=1
x = z
所以这时候就是当快指针走一圈的时候到p点相遇时剩下的距离z就和直线距离x相等。
所以我们这时就可以使用两个指针都是一格一格的走一个从起点出发,一个从p点出发当两个指针相遇时,相遇的那个点就是环的入口,这时我们进行返回即可。
(只是数学推算,个人还存在没有想的很透彻的地方)