返回
LeetCode 141:解开环形链表的秘密
后端
2024-01-08 23:56:03
邂逅环形链表
环形链表是一种特殊的数据结构,它与普通链表的不同之处在于,链表的尾节点指向的不是空,而是链表中的某个节点,从而形成一个闭环。环形链表在编程中经常被用来解决特定问题,如判断链表是否有环、查找环的入口节点等等。
LeetCode 141 题正是考察了环形链表的基本性质。题目给定一个链表的头节点 head,要求判断链表中是否存在环。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。
破解之法
面对环形链表,我们可以采用多种方法来判断其是否存在环。以下是最常见的两种方法:
1. 龟兔赛跑法
这种方法的灵感来源于著名的龟兔赛跑故事。我们使用两个指针,分别命名为「乌龟」和「兔子」。「乌龟」每次移动一步,而「兔子」每次移动两步。如果「兔子」在赛跑过程中追上了「乌龟」,则说明链表中存在环。这是因为「兔子」比「乌龟」跑得快,如果链表中没有环,那么「兔子」最终会跑到链表的末尾,而「乌龟」则会慢悠悠地跟在后面。但是,如果链表中存在环,那么「兔子」就会在环中不断循环,最终追上「乌龟」。
def has_cycle(head):
"""
判断链表中是否存在环。
参数:
head: 链表的头节点。
返回:
如果链表中存在环,返回 True;否则,返回 False。
"""
# 如果链表为空,则不存在环。
if not head:
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
# 如果「乌龟」和「兔子」相遇,则链表中存在环。
return True
2. 集合法
这种方法相对简单粗暴。我们使用一个集合来存储已经访问过的节点。当我们遍历链表时,如果发现某个节点已经存在于集合中,则说明链表中存在环。这是因为在没有环的情况下,我们只会在链表中遇到每个节点一次。
def has_cycle(head):
"""
判断链表中是否存在环。
参数:
head: 链表的头节点。
返回:
如果链表中存在环,返回 True;否则,返回 False。
"""
# 如果链表为空,则不存在环。
if not head:
return False
# 创建一个集合来存储已经访问过的节点。
visited = set()
# 遍历链表。
while head:
# 如果当前节点已经存在于集合中,则链表中存在环。
if head in visited:
return True
# 将当前节点添加到集合中。
visited.add(head)
# 移动到下一个节点。
head = head.next
# 如果遍历到链表的末尾,则链表中不存在环。
return False
结语
环形链表是一个经典的数据结构问题,也是 LeetCode 中的常见题目。通过本文的讲解,相信你对环形链表有了一个更加深入的理解。掌握了判断环形链表的方法,你就可以轻松应对相关的问题,在编程面试中脱颖而出。