环形链表——刷题打卡:巧妙运用指针技巧
2024-02-12 14:32:06
在编程的世界里,链表是一种常见的数据结构,它由一组节点组成,每个节点都包含数据和指向下一个节点的指针。环形链表是一种特殊类型的链表,其中最后一个节点的指针指向链表中的第一个节点,形成一个闭合的环。环形链表的判定是算法面试中经常考察的题目之一,掌握其判定技巧可以帮助我们解决更复杂的算法问题。
1. 快慢指针法:追逐竞赛
快慢指针法是一种判定环形链表的经典方法。该方法利用了链表的循环性质,即如果链表中存在环,那么从链表中的任意位置出发,沿着next指针移动,最终都会回到起始位置。
快慢指针法的核心思想是使用两个指针,一个称为快指针,另一个称为慢指针。快指针每次移动两个节点,而慢指针每次移动一个节点。如果链表中存在环,那么快指针最终会追上慢指针,相遇点就是环的入口节点。
def has_cycle(head):
"""
判定链表中是否存在环。
参数:
head: 链表的头节点。
返回:
如果链表中存在环,则返回 True;否则,返回 False。
"""
# 如果链表为空或只有一个节点,则不存在环。
if head is None or head.next is None:
return False
# 初始化快指针和慢指针。
slow = head
fast = head.next
# 循环遍历链表,直到快指针追上慢指针或到达链表尾部。
while slow != fast and fast is not None and fast.next is not None:
# 移动快指针和慢指针。
slow = slow.next
fast = fast.next.next
# 如果快指针和慢指针相遇,则链表中存在环。
return slow == fast
2. 哈希表法:标记节点
哈希表法也是一种判定环形链表的方法。该方法利用了哈希表的数据结构,将链表中的节点作为键值对存储在哈希表中。如果某个节点已经存储在哈希表中,那么链表中就存在环,环的入口节点就是该节点。
def has_cycle(head):
"""
判定链表中是否存在环。
参数:
head: 链表的头节点。
返回:
如果链表中存在环,则返回 True;否则,返回 False。
"""
# 初始化哈希表。
hash_table = set()
# 循环遍历链表,将每个节点存储在哈希表中。
while head is not None:
# 如果当前节点已经存储在哈希表中,则链表中存在环。
if head in hash_table:
return True
# 将当前节点存储在哈希表中。
hash_table.add(head)
# 移动到下一个节点。
head = head.next
# 如果遍历完整个链表,没有发现环,则链表中不存在环。
return False
3. 弗洛伊德循环检测法:巧妙的步调
弗洛伊德循环检测法是一种基于快慢指针法的环形链表判定方法。该方法利用了链表的循环性质,即如果链表中存在环,那么从链表中的任意位置出发,沿着next指针移动,最终都会回到起始位置。
弗洛伊德循环检测法与快慢指针法的区别在于,它只使用了一个指针,称为乌龟指针。乌龟指针每次移动一步,直到它遇到另一个节点或到达链表尾部。如果乌龟指针遇到了另一个节点,那么链表中存在环,环的入口节点就是该节点。
def has_cycle(head):
"""
判定链表中是否存在环。
参数:
head: 链表的头节点。
返回:
如果链表中存在环,则返回 True;否则,返回 False。
"""
# 如果链表为空或只有一个节点,则不存在环。
if head is None or head.next is None:
return False
# 初始化乌龟指针。
slow = head
# 循环遍历链表,直到乌龟指针遇到另一个节点或到达链表尾部。
while slow is not None:
# 移动乌龟指针。
slow = slow.next
# 如果乌龟指针遇到另一个节点,则链表中存在环。
if slow in hash_table:
return True
# 将当前节点存储在哈希表中。
hash_table.add(slow)
# 如果遍历完整个链表,没有发现环,则链表中不存在环。
return False
结语
环形链表的判定是算法面试中经常考察的题目之一,掌握其判定技巧可以帮助我们解决更复杂的算法问题。快慢指针法、哈希表法和弗洛伊德循环检测法都是判定环形链表的常用方法,每种方法都有其优缺点。在实际应用中,我们可以根据具体情况选择合适的方法来判定环形链表。