环形链表(双指针的应用)

289 阅读2分钟

上题(题号:142)

image.png 简而言之就是要我们找出链表的环的入口,无环则返回null

分析

如果链表中存在环,执行遍历操作时指针会一直在环里打转出不来,利用这个特性可以设置一快一慢俩指针,当俩指针相遇时,代表该链表存在环,同时注意快指针比慢指针只快1步(为了防止快指针移动时跳过慢指针导致俩指针无法相遇)。

解决了判断是否存在环的问题,剩下的就是求出环入口的位置了。

我们定义在未相遇前fast = fast.next.next;slow = slow.next;head节点到环入口的举例为x,环入口到相遇位置的距离为y,相遇位置到环入口的举例为z。为什么相遇位置一定在环内:快指针走的比慢指针快,进了环之后就出不来了,只能在环内相遇。

慢指针走的路程:x+y 快指针走的路程x+y+n(y+z) 所以有 2(x+y) = x+y+n(y+z)化简得x = (n-1)(y+z)+z且n至少等于1(等于零的话说明快慢指针走的一样多,不符合俩指针的速度比)。 n = 1时,易得x =z 。稍加思考,快指针:2(x+y),减去未入环时的x,在环内走了x+2y的路程,再减去环入口到相遇位置的y,只剩下x+y了,再从相遇节点出发走x步,必然到达环入口(因为再走y步就到相遇节点了),所以再在头结点和相遇节点处分别定义一个指针index1,index2。令index1 = index1.next,index2 = index2.next,待到index1 = index2 时,return index1/index2 即可

完整代码如下:

image.png

关于while循环的循环条件的说明: 由于 fast = fast.next.next;fast指针一次前进两次,如果在链表无环的情况fast前进两次后刚好到达链表末尾即fast == null,那么fast.next 会报空指针异常,所以fast != null不能删去,同理,删去fast != null,当fast恰好时最后一个结点时,循环体中fast.next.next会报空指针异常.