给定一个单链表,判断其中是否有环,已经是一个比较老同时也是比较经典的问题,在网上搜集了一些资料,然后总结一下大概可以涉及到的问题,以及相应的解法。

首先,关于单链表中的环,一般可能涉及到以下几个问题:

  1、给一个单链表,判断其中是否有环的存在;

  2、如果存在环,找出环的入口点;

  3、计算环的长度;

下面,我将针对上面这几个问题一一给出解释。

 

1、判断时候有环(链表头指针为head)

  对于这个问题我们可以采用 “快慢指针” 的方法。就是有两个指针 fast 和 slow,开始的时候两个指针都指向链表头 head,然后在每一步操作中 slow 向前走一步即:slow = slow→next,而 fast 每一步向前两步即:fast = fast→next→next。

  由于 fast 要比 slow 移动的快,如果有环,fast 一定会先进入环,而 slow 后进入环。当两个指针都进入环之后,经过一定步的操作之后二者一定能够在环上相遇,并且此时 slow 还没有绕环一圈,也就是说一定是在 slow 走完第一圈之前相遇。

2、找出环的入口点

判断是否有环java 判断是否有环_快慢指针

  当 fast 和 slow 相遇时,slow 肯定还没有走完链表,假设 fast 已经在环内循环了n(1<= n)圈。假设 slow 这时总共走了 s 步,则 fast 走了 2 * s 步;又由于 fast 走过的步数 = s + n * r(s + 在环上多走的n圈),则有下面的等式:

    2 * s = s + n  * r (1)

    s = n * r (2)

  如果假设整个链表的长度是 L,入口和相遇点的距离是 x,起点到入口点的距离是 a ,则有:

    a + x = s = n * r   (3)

    r = L - a  (4)

    a + x = (n - 1) * r + r  = (n - 1) * r + (L - a)   (5)

    a = (n - 1) * r + (L -a -x)   (6)

  集合式子(5)可以看出,从链表起点 head 开始到入口点的距离 a,等于从 slow 和 fast 的相遇点到入口点的距离 +  (n - 1) * r 。

  因此我们就可以分别用一个指针(ptr1, prt2),同时从 head 与 “slow和fast 的相遇点” 出发,每一次操作走一步,直到ptr1 == ptr2,此时的位置也就是入口点!

3、计算环的长度

  根据2可以得到环的入口点,则环的长度就非常容易得到了,用一个指针在入口点出发,每一次操作走一步,直到再次回到入口点,就可以得到环的长度了!