判断链表是否有环
判断链表是否有环有两种思路。
- 利用set()集合,每经过一个节点,就将该节点保存在set()集合中,如果该链表遍历至空,则表示无环。如果该链表的节点第二次出现在set()集合中,则表示有环。
def hasCycle(head):
"""
:type head: ListNode
:rtype: bool
"""
if not head:
return False
seen = set()
p = head
while p:
if p not in seen:
seen.add(p)
else:
return True
p = p.next
else:
return False
这种做法的时间复杂度是O(N),空间复杂度也是O(N)。
但是我们有更好的做法。
2. 利用快慢指针。快慢指针指的是,快指针每次越过两个节点,慢指针每次越过一个节点。如果快指针为空了,则表示链表无环,如果快慢指针相遇了,则表示有环。为什么快慢指针相遇了,则表示有环呢?我们可以这样想,如果两个人在环形跑道上跑步,a速度是1m/s,b速度是2m/s,一圈200米,200秒后,a跑完了一圈,b恰好也跑完了两圈,会在起点相遇。
def hasCycle(head):
"""
:type head: ListNode
:rtype: bool
"""
if not head:
return False
fast = slow = head
while fast.next and fast.next.next:
fast = fast.next.next
slow = slow.next
if fast is slow:
return True
else:
return False
返回链表环的第一个入点
寻找链表环的第一个入口点,同样有两种思路。
- 利用set()集合,每经过一个节点,就将该节点保存在set()集合中,如果该链表遍历至空,则表示无环。如果该链表的节点第二次出现在set()集合中,第一个第二次出现在set()集合中的节点即使链表环的第一个入口点。
def detectCycle(head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head:
return None
seen = set()
p = head
while p:
if p not in seen:
seen.add(p)
else:
return p
p = p.next
- 利用快慢指针。快慢指针指的是,快指针每次越过两个节点,慢指针每次越过一个节点。如果快指针为空了,则表示链表无环,如果快慢指针相遇了,则表示有环。为什么快慢指针相遇了,则表示有环呢?我们可以这样想,如果两个人在环形跑道上跑步,a速度是1m/s,b速度是2m/s,一圈200米,200秒后,a跑完了一圈,b恰好也跑完了两圈,会在起点相遇。
没有很好的理解为什么。暂时不写。