Given a linked list, return the node where the cycle begins. If there is no cycle, return null
.
Follow up:
Can you solve it without using extra space?
先用一个指针走一步,另一个指针走两步的方法判断是否存在回路,如果存在,则将其中一个指针指回头结点,然后两个指针一步一步往下走,走到相遇的地方,就是指针环路所在节点。
这个问题就好像是追及问题:
两个小人都从A地出发,一个走的速度是另一个的两倍,走的快的人在跑道上绕了n圈后和走的慢的在B地相遇(跑道长度为k),此时可以列出等式:vt + nk = 2vt (nk是速度快的小人多走的路程),那么可得vt = nk,由于慢的小人从A到B总共走了vt,所以可得 l1 + l2 = nk。 本题问的是环路所在节点,即图中红色部分,所以接着推导上式: l1 + l2 = (n - 1)k + k 即 l1 = (n - 1)k + (k - l2)。 k - l2 即为从B点绕跑道逆时针跑到红点的距离,那么可得出一个指针从A点跑,另一个指针从B点跑,此时他们用一样的速度vt,总能在红点处相遇。
Source
/**
* 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) {
if(head == null || head.next == null) return null;
boolean flag = false;
ListNode p = head, q = head;
while(q != null && q.next != null){
p = p.next;
q = q.next.next;
if(p == q){
flag = true;
p = head;
break;
}
}
if(flag == false) return null;
else{
while(p != q){
p = p.next;
q = q.next;
}
return q;
}
}
}
Test
public static void main(String[] args){
ListNode a = new ListNode(1);
a.next = new ListNode(4);
a.next.next = new ListNode(3);
a.next.next.next = new ListNode(2);
ListNode b = a.next.next.next;
b.next = a.next;
System.out.println(new Solution().detectCycle(a).val);
}