环形链表 II

QUESTION:

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

说明:不允许修改给定的链表。

示例 1:

输入:head = [3,2,0,-4], pos = 1 输出:tail connects to node index 1 解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0 输出:tail connects to node index 0 解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1 输出:no cycle 解释:链表中没有环。

进阶: 你是否可以不用额外空间解决此题?

EXPLANATION:

这道题目和环形链表一有很多的相似之处。首先,你需要判断当前链表是不是一个环形,就需要用到环形链表1中的判断算法。在判断出来了之后就需要考虑怎么样才能得到进入循环的第一个节点问题。可以假设前面是为x,循环的长度为y。循环的长度y我们是可以得到的,通过循环当时的slow就可以。那么我们就可以得到一个等式,其实就是x+y其实就是回到了第一个点。那么我们就可以让fast指针先走y步,然后让slow和fast一起走,每次走一步,那么两者第一次相遇肯定就是第一次循环的点了。
逻辑:
1.首先通过双指针slow,fast的方式判断出链表是否是环形
2.如果是环形链表,通过slow指针,计算出循环的长度y
3.将slow和fast都放在head位置,让fast先走y步,那么剩下的就是x步回到第一个点
4.让slow走x步,必然会和fast相遇,那么只要判断两者是否相等就可以得到x了

SOLUTION:

public class Solution {
    public ListNode detectCycle(ListNode head) {
        if(head==null) return null;
        ListNode slow = head;
        ListNode fast = head;
        ListNode tmp = null;
        while (true){
            if(fast == null || fast.next==null || slow==null) return null;
            slow = slow.next;
            fast = fast.next.next;
            if(slow==fast){
                tmp = slow;
                break;
            }
        }
        int count = 1;
        while (tmp.next!=slow) {
            count++;
            tmp = tmp.next;
        }
        slow = head;fast = head;
        for(int i= 0;i<count;i++) fast = fast.next;
        while (slow!=fast) {
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }
}