返回

如何巧用快慢指针,秒杀“环形链表 II”难题

前端

在算法学习的浩瀚海洋中,环形链表无疑是一颗璀璨的明珠,它以其独特的数据结构和复杂性,吸引着无数算法爱好者的目光。而“环形链表 II”这道经典难题,更是将环形链表的概念推向了一个新的高度。

解决“环形链表 II”难题的关键,在于理解环形链表的本质和巧妙运用快慢指针的技巧。快慢指针是一种遍历链表的经典算法,它利用不同速度的指针,在链表中穿梭。在“环形链表 II”中,快指针的速度为慢指针的两倍,这一速度差为我们判断环形链表是否存在,以及确定环形链表的起始点提供了重要的线索。

判断环形链表是否存在

首先,我们需要判断给定的链表是否为环形链表。快慢指针在此阶段派上了用场。快指针每移动一步,慢指针移动半步。如果链表中存在环形结构,那么快指针最终会追上慢指针。此时,我们可以断定链表存在环形结构。

确定环形链表的起始点

如果链表中存在环形结构,那么下一步就是确定环形链表的起始点。此时,快慢指针相遇于环形结构中某一点。我们令相遇点为 X,链表头为 A,慢指针从 A 开始,每次移动一步;快指针从 X 开始,每次移动两步。当慢指针和快指针再次相遇时,相遇点即为环形链表的起始点。

证明

假设快慢指针在图中圆点处相遇,则此时:

因为快指针的速度为慢指针的2倍,所以快指针走过的距离为慢指针的两倍。

慢指针走过的距离 = 从头结点到 X 处的距离 + X 到相遇点处距离

快指针走过的距离 = 从头结点到 X 处的距离 + X 到相遇点处距离 + 相遇点处距离到环形链表的起点处距离 + 环形链表的起点处距离到 X 处的距离

因此,我们有:

2 * (从头结点到 X 处的距离 + X 到相遇点处距离) = 从头结点到 X 处的距离 + X 到相遇点处距离 + 环形链表的起点处距离到 X 处的距离 + 环形链表的起点处距离到头结点的距离

化简后得到:

从头结点到 X 处的距离 = 环形链表的起点处距离到 X 处的距离

这表明,从头结点到 X 处的距离等于从环形链表的起点处到 X 处的距离。因此,慢指针和快指针再次相遇时,相遇点即为环形链表的起始点。

代码实现

def detectCycle(head):
    if not head or not head.next:
        return None

    slow = head
    fast = head

    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next

        if slow == fast:
            break

    if slow != fast:
        return None

    slow = head

    while slow != fast:
        slow = slow.next
        fast = fast.next

    return slow

通过巧妙运用快慢指针技巧,我们可以高效地解决“环形链表 II”难题,判定环形链表的存在,并准确找到环形链表的起始点。这一算法不仅在学术研究领域具有重要意义,在实际软件开发中也得到了广泛的应用。希望这篇博文能够带你领略算法之美,激发你的学习热情。