若单链表中存在环,则环肯定在单链表的尾部,如果通过一个指针遍历单链表,最终这个指针会在单链表尾部的环中不断循环,其实质问题是判断这个指针是否落在一个环中。
这种问题我们可以联想到时钟,虽然时针和分针以不同的间隔旋转,但它们必须会有相遇的时候,如果时钟不是一个圆,它们就没有相遇的时候了。
所以我们可以设置两个指针,慢指针每次前进一个节点,快指针每次前进两个节点,如果它们相遇,则单链表必定存在环,否则不存在环。
那么如果找到环的入口点呢,这里需要进行几步数学推导,首先看下图:
假设单链表的起点是A,环的入口点是B,慢指针和快指针第一次相遇的点是C, 注意慢指针和快指针第一次相遇的时候,慢指针还没有遍历完整个单链表,假设慢指针此时前进的距离为s,快指针此时前进的距离为2s
若环的长度为r, A和入口点B之间的距离为k, 入口点距第一次相遇点C的距离为l, C距链表的尾部的距离为h, (也就是剩余的环的长度),
假设两个指针相遇前,快指针已经围圆环走了n圈,
2s = s + nr;
从而 s = nr;
k + l = nr
k = nr - l
k = (n-1)r + (r - l)
最终有 k = (n-1)r + h
也就是说,若有一个指针从A节点开始遍历,另一个指针从相遇点C开始遍历,则在它们必然会在入口点B相遇。