目录:
目的
{3,2,0,-4}, 1 这表示有环即为True。-1代表无环False,其它的数字代表有环。
思路
这个任务是判断一个链表是否包含环(循环路径),避免在操作链表时出现无限循环的问题。可以简单理解为龟兔赛跑(Floyd 判圈算法),兔子快,乌龟慢,但路是圈圈(有环)兔子必定追上。路有终点(无环),兔子先到头不等乌龟了。
准备阶段:
-
参赛选手:
- 乌龟(慢指针slow): 每次只走一步,慢悠悠的。slow = head
- 兔子(快指针fast): 每次跳两步,飞快地往前冲。fast = head.next
- 为什么这样安排?
- 让兔子先跳一步,确保开始时不会立刻相遇(
head != head.next
)。 - 保证比赛开始时有足够的间隔,能正确判断链表中是否有环。
- 让兔子先跳一步,确保开始时不会立刻相遇(
-
特例处理:
- 如果这条路上只有一个点(链表为空head == None或只有一个节点head.next == None),直接告诉你没环,环的形成至少需要两个节点,因此直接返回
False
。
- 如果这条路上只有一个点(链表为空head == None或只有一个节点head.next == None),直接告诉你没环,环的形成至少需要两个节点,因此直接返回
比赛规则:
只要兔子还没跑出链表(
fast != None
且fast.next != None
),比赛继续。
- 为什么检查两个条件?
fast
: 如果fast == None
,说明兔子已经跑到了链表的尽头,没有环。fast.next
: 是兔子跳两步时需要访问的下一个节点。fast.next == None
,说明兔子已经没有“下一步”可以跳,也意味着链表没有环。
比赛开始:
- 乌龟稳步前进: 走一步,代表慢速slow = slow.next。
- 兔子飞速跳跃: 跳两步,代表快速移动fast = fast.next.next。
- 相遇时刻: 如果乌龟和兔子相遇,比赛结束(
slow == fast
)。说明链表有环(True),退出循环。 - 为什么一定会相遇?
- 如果链表是闭环,兔子因为步伐更快,最终会在环内兜圈,追上乌龟。
比赛结束:
如果比赛结束了(循环退出),乌龟和兔子没有相遇,说明兔子跑到了头,链表没有环(False)。
复杂度
-
时间复杂度:O(n)
- 每次兔子和乌龟各走一段路,总路程不会超过链表长度的两倍。
-
空间复杂度:O(1)
- 只用了两只小动物(两个指针变量),省吃俭用,不多花内存。
记忆秘诀
- 乌龟走一步,兔子跳两步。
- 链表有环,相遇无误。
- 链表无环,兔子先停步。
python代码
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
#
# @param head ListNode类
# @return bool布尔型
#
class Solution:
def hasCycle(self , head: ListNode) -> bool:
if not head or not head.next:
# 比赛没法开始,直接判无环
return False # 如果链表为空或者只有一个节点,则无环
slow = head # 慢指针 # 乌龟
fast = head.next # 快指针 # 兔子
# 快慢指针开始移动
while fast and fast.next: # 兔子还没跑出赛道
slow = slow.next # 慢指针走一步 # 乌龟走一步
fast = fast.next.next # 快指针走两步 # 兔子跳两步
# 乌龟和兔子相遇,有环
if slow == fast:
return True # 快慢指针相遇,说明有环
return False # 如果没有相遇,则无环 # 兔子跑出赛道,无环
* 欢迎大家探讨新思路,能够更好的理解和记忆