给定一个单链表,判断其中是否有环,已经是一个比较老同时也是比较经典的问题,在网上搜集了一些资料,然后总结一下大概可以涉及到的问题,以及相应的解法。
首先,关于单链表中的环,一般可能涉及到以下几个问题:
1、给一个单链表,判断其中是否有环的存在;
2、如果存在环,找出环的入口点;
3、计算环的长度;
下面,我将针对上面这几个问题一一给出解释。
1、判断时候有环(链表头指针为head)
对于这个问题我们可以采用 “快慢指针” 的方法。就是有两个指针 fast 和 slow,开始的时候两个指针都指向链表头 head,然后在每一步操作中 slow 向前走一步即:slow = slow→next,而 fast 每一步向前两步即:fast = fast→next→next。
由于 fast 要比 slow 移动的快,如果有环,fast 一定会先进入环,而 slow 后进入环。当两个指针都进入环之后,经过一定步的操作之后二者一定能够在环上相遇,并且此时 slow 还没有绕环一圈,也就是说一定是在 slow 走完第一圈之前相遇。
2、找出环的入口点
当 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可以得到环的入口点,则环的长度就非常容易得到了,用一个指针在入口点出发,每一次操作走一步,直到再次回到入口点,就可以得到环的长度了!