返回

多重视角解析链表环结构的入口结点

前端

揭秘快慢指针法:寻找链表环结构入口

导语

链表环结构是一种常见的数据结构,它由一个循环引用的节点序列组成。寻找链表环结构的入口结点是一个经典的问题,也是面试中经常被问到的难题。本文将深入浅出地讲解一种优雅的算法——快慢指针法,带你直观地理解如何破解这一难题。

快慢指针法:步入赛道,寻觅起点

想象一下,你正置身于一个庞大的赛道上,赛道上运动员们奋力追逐。你的目标是找到赛道的入口,也就是起点。与其他运动员不同的是,你拥有两种奔跑模式:慢速快速

  • 慢速模式: 你以正常的速度前进,一步一步地沿着赛道探索。
  • 快速模式: 你以两倍的速度前进,快速地追赶其他运动员。

比赛开始,你从起点出发,以慢速前进。同时,另一个运动员以快速前进。你们沿着赛道奔跑,不断地超越对方。

突然,你们在某个地方相遇了!这一时刻,你意识到自己已经跑了一圈,回到了起点。

相遇时刻:缩小范围

相遇的瞬间,你立即切换到快速模式,继续前进。而另一个运动员仍然以慢速前进。你们再次相遇时,你已经跑了两圈,而另一个运动员只跑了一圈。

就这样,你们不断地相遇,每次相遇时,你都会切换到快速模式,继续前进。而另一个运动员仍然以慢速前进。随着时间的推移,你们之间的距离会越来越大。

最终,你将超越另一个运动员,再次回到起点。此时,你已经跑完了整条赛道,而另一个运动员还在后面慢慢地前进。

本质揭秘:不断缩小环入口范围

快慢指针法的精髓在于,它将环入口结点查找问题转化为一个不断缩小范围的问题。每次相遇时,你都会缩小环入口结点的范围。最终,你将找到环入口结点,也就是起点。

具体来说:

  • 当快慢指针第一次相遇时,你已经跑了一圈,回到了起点。此时,你可以确定,环入口结点一定在起点和第一次相遇点之间。
  • 你切换到快速模式,继续前进。当你们再次相遇时,你已经跑了两圈,而另一个运动员只跑了一圈。此时,你可以确定,环入口结点一定在第一次相遇点和第二次相遇点之间。
  • 这样不断地相遇和缩小范围,最终,你将找到环入口结点。

算法代码示例

def find_cycle_entry(head):
    """
    寻找链表环结构的入口结点

    Args:
        head (ListNode): 链表的头结点

    Returns:
        ListNode: 环入口结点
    """

    if not head:
        return None

    slow = head
    fast = head

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

    # 如果不存在环,返回 None
    if not fast or not fast.next:
        return None

    # 确定环的存在
    slow = head

    # 快慢指针相遇后,继续前进,直到再次相遇,此时为环入口
    while slow != fast:
        slow = slow.next
        fast = fast.next

    return slow

时间复杂度分析

快慢指针法的时间复杂度 为O(n),其中n是链表的长度。

证明:

  1. 快指针和慢指针都从链表的头部开始移动。
  2. 快指针的速度是慢指针的两倍。
  3. 因此,快指针会比慢指针先到达环的入口结点。
  4. 当快指针第一次到达环的入口结点时,慢指针还在环外。
  5. 快指针继续沿着环前进,直到第二次到达环的入口结点。
  6. 此时,慢指针也到达了环的入口结点。
  7. 快指针和慢指针在环的入口结点相遇。
  8. 快指针和慢指针继续沿着环前进,直到第二次相遇。
  9. 此时,快指针已经绕环走了两圈,而慢指针只绕环走了】一圈,距离相差一个环长。
  10. 继续前进,快指针和慢指针的距离会逐渐缩小,最终在环入口相遇。
  11. 从相遇点到环入口的距离为环长。
  12. 因此,快慢指针法的时间复杂度为O(n),其中n是链表的长度。

常见问题解答

  1. 为什么快慢指针一定会相遇?

    • 如果链表中存在环,那么快指针最终会追上慢指针。因为快指针的速度是慢指针的两倍,所以当快指针绕环一圈时,慢指针只绕环了半圈。
  2. 如果链表中不存在环,快慢指针法会发生什么?

    • 如果链表中不存在环,那么快指针最终会到达链表的末尾。此时,快指针和慢指针都不会再前进,算法终止,返回 None。
  3. 快慢指针法是否适用于单链表?

    • 是的,快慢指针法适用于单链表。即使单链表中存在环,快指针最终也会追上慢指针。
  4. 快慢指针法是否可以用来计算环的长度?

    • 是的,快慢指针法可以用来计算环的长度。当快指针第一次到达环入口时,慢指针还在环外。快指针继续沿着环前进,直到第二次到达环入口,此时快指针已经绕环走了一圈。因此,环的长度为快指针和慢指针相遇时,快指针所前进的距离。
  5. 快慢指针法是否可以用来判断链表中是否存在环?

    • 是的,快慢指针法可以用来判断链表中是否存在环。如果快指针和慢指针相遇,则链表中存在环。否则,链表中不存在环。

结论

快慢指针法是一种巧妙而高效的算法,用于查找链表环结构的入口结点。它基于直观的概念,通过让指针不断相遇并缩小范围来解决问题。掌握这一算法不仅有助于解决面试难题,更能加深你对数据结构和算法本质的理解。