Leetcode142.环形链表 II——快慢指针和Floyd算法

引入

142.环形链表 II的题目如下:

142.环形链表 II
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。
在这里插入图片描述

最简单的方法就是用一个HashSet去保存访问过的节点,如果访问到最后是null,说明不是环形的;否则就能从Set中找到重复元素。这样做的时间复杂度是O(N),空间复杂度是O(N),需要一个额外的Set保存。

此外,还有额外的一种方法,就是使用快慢指针,快指针比慢指针每次多走一个Node。该方法在234. 回文链表中使用过。

本题使用基于快慢指针的Floyd算法。

Floyd算法

Floyd 的算法被划分成两个不同阶段 。

第一阶段:找出是否有环。
如果产生环,因为快指针总是比慢指针快1步,所以总会在小于环长度的迭代中追上慢指针(即超一圈)。
第一阶段复杂度是O(N),不需要额外空间。
我们可以试想下面的场景:
在这里插入图片描述
环节点从0到C-1编号,非环节点从-F到-1编号。
一开始,经过F次迭代,慢指针到达了节点0,此时快指针到达了h节点,其中h≡F(mod C)。现在,只需要C-h次迭代,快指针就能追上慢指针(假设慢指针不动,相对的,快指针只需要走C-h步)。
这一总的过程,经历了F+h步,是小于等于链表长度的。
在这里插入图片描述

第二阶段:找出成环的那个节点。
找到成环节点的方法如下:
给定阶段 1 找到的相遇点,阶段 2 将找到环的入口。首先我们初始化额外的两个指针: ptr1 ,指向链表的头, ptr2 指向相遇点。然后,我们每次将它们往前移动一步(相同的速度),直到它们相遇,它们相遇的点就是环的入口,返回这个节点。
在这里插入图片描述
我们现在来证明为什么他们相遇的节点就是成环节点
在这里插入图片描述

我们来看,在第一次快慢指针相遇状态下,快指针在什么位置?
首先,快指针经过2F步,到达了h节点,其中h≡F(mod C),此时慢指针刚好经过F步到达0节点。
然后,快指针和慢指针相遇需要C-h次移动,也就是说相遇点到了C-h处。也就是阶段2的ptr1需要在C-h处出发。

现在来看ptr2到0节点处,需要F步。
ptr1到达0节点处,需要C-(C-h)步,就是h步。
其中h≡F(mod C),证明完毕。

结果表明,两个节点ptr1和ptr2再次相遇的节点就是0节点。

Leetcode题解

阶段一:快慢指针追击。

	private ListNode getIntersect(ListNode head) {
        ListNode tortoise = head;
        ListNode hare = head;
        while (hare != null && hare.next != null) {
            tortoise = tortoise.next;
            hare = hare.next.next;
            if (tortoise == hare) {
                return tortoise;
            }
        }

        return null;
}

阶段二:找到环形节点。

	public ListNode detectCycle(ListNode head) {
        if (head == null) {
            return null;
        }
        ListNode intersect = getIntersect(head);
        if (intersect == null) {
            return null;
        }
        ListNode ptr1 = head;
        ListNode ptr2 = intersect;
        while (ptr1 != ptr2) {
            ptr1 = ptr1.next;
            ptr2 = ptr2.next;
        }

        return ptr1;
    }
发布了364 篇原创文章 · 获赞 324 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/No_Game_No_Life_/article/details/103819478