我用快慢指针解决LeetCode 142. Linked List Cycle II
2023-10-25 16:55:32
LeetCode 142:链表环检测和入口识别
概述
在计算机科学中,链表是一种广泛使用的线性数据结构,它由一系列通过指针相互连接的节点组成。链表环 是一种特殊情况,其中链表中某个节点指向前面某个节点,形成一个闭合的循环。检测链表环的存在对于数据结构的完整性至关重要。LeetCode 142 是一道经典算法题,它要求你判断一个链表中是否存在环路,如果存在,则返回环路的入口节点。
解题思路
解决 LeetCode 142 问题的常用方法有两种:使用集合和使用快慢指针。
1. 使用集合
这种方法利用集合的特性,即元素不重复且插入和查询的效率都很快,来记录访问过的节点。算法步骤如下:
- 创建一个空集合
visited
来存储访问过的节点。 - 从头节点开始遍历链表。
- 对于每个访问的节点,如果它已经在
visited
集合中,则说明存在环路,并返回该节点。 - 如果未找到环路,则将当前节点添加到
visited
集合中,并继续遍历链表。
代码示例:
def has_cycle_using_set(head):
"""
:type head: ListNode
:rtype: bool
"""
visited = set() # 用来记录访问过的节点
while head:
if head in visited:
return True
visited.add(head)
head = head.next
return False
2. 使用快慢指针
这种方法利用快慢指针来判断是否存在环路。快指针每次移动两步,慢指针每次移动一步。如果存在环路,则快指针和慢指针最终会相遇。相遇时,慢指针重新从头开始移动,快指针继续移动。当快指针再次与慢指针相遇时,相遇点就是环路入口节点。
代码示例:
def has_cycle_using_fast_slow_pointers(head):
"""
:type head: ListNode
:rtype: bool
"""
if not head or not head.next:
return False
slow = head
fast = head.next
while slow != fast:
if not fast or not fast.next:
return False
slow = slow.next
fast = fast.next.next
slow = head
while slow != fast:
slow = slow.next
fast = fast.next
return True
方法比较
方法 | 时间复杂度 | 空间复杂度 |
---|---|---|
使用集合 | O(n) | O(n) |
使用快慢指针 | O(n) | O(1) |
结论
LeetCode 142 是一个经典算法题,要求判断一个链表中是否存在环路,如果存在,则返回环路的入口节点。可以使用集合或快慢指针这两种方法来解决这个问题。集合方法空间复杂度较低,但时间复杂度较高。快慢指针方法时间复杂度较低,但空间复杂度较高。你可以根据具体情况选择合适的方法。
常见问题解答
-
什么是链表环?
链表环是指链表中某个节点指向前面某个节点,形成一个闭合的循环。
-
为什么检测链表环很重要?
检测链表环很重要,因为它可以防止数据结构出现问题,例如无限循环或内存泄漏。
-
使用集合方法时,为什么需要记录访问过的节点?
使用集合方法时,需要记录访问过的节点,因为当遇到已经访问过的节点时,说明存在环路。
-
为什么快慢指针方法的慢指针在相遇后需要重新从头开始移动?
快慢指针方法的慢指针在相遇后需要重新从头开始移动,是为了确定环路入口节点。慢指针从头开始移动,快指针继续在环内移动。当快指针再次与慢指针相遇时,相遇点就是环路入口节点。
-
快慢指针方法什么时候会失败?
快慢指针方法可能会失败,当链表中存在多个环路时。这种情况下,该方法将返回第一个环路的入口节点,而不是最后一个环路的入口节点。