快慢指针方法
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow=slow.next;
fast=fast.next.next;
if(slow==fast){
ListNode index1=head;
ListNode index2=slow;
while(index1!=index2){
index1=index1.next;
index2=index2.next;
}
return index1;
}
}
return null;
}
}
需要解决的问题
解决方法
- 设定快慢指针slow和fast,slow每次走一步,fast每次走两步,如果链表有环,slow和fast一定能在环中相遇。因为slow和fast的相对来说是slow原地不动,fast每次向前走一步,所以fast一定能在环中追上slow。
- 假设链表中有环,设head到环的入口节点数为x,入口到相遇点的节点数为y,相遇点到入口的节点数为z。那么当slow和fast相遇时slow走过的节点数为x+y,fast走过的节点数为x+n(y+z),并且fast走过的节点数是slow的两倍。所以有x=(n-1)(y+z)+z,意味着从head出发一个index1,从相遇点出发一个index2,当index1和index2相遇时,他们指向的节点就是环的入口。
- 其中有一个疑惑的点在于slow和fast相遇的时候,为什么slow走过的节点数是x+y,而不是slow也在环里转了几圈。假设slow进入环的那一刻就原地不动,那么fast每次向前走一步,fast肯定不用一圈的时间就可以追上slow,所以slow和fast在slow进入环之后不到一圈的时间就会相遇。
哈希数组方法
public class Solution {
public ListNode detectCycle(ListNode head) {
Set<ListNode> set = new HashSet<>();
ListNode cur=head;
while(cur!=null){
if(!set.add(cur)){
return cur;
}
cur=cur.next;
}
return null;
}
}