题目要求
给定一个链表,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
进阶:你能用 O(1)(即,常量)内存解决此问题吗?
解题思路
方法一:字典(hash表)
用字典记录已访问过的节点:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def hasCycle(self, head):
"""
:type head: ListNode
:rtype: bool
"""
dic = {}
while head:
# 判断head是否已经存在于dic中
if head in dic:
return True
dic[head] = 1
head = head.next
"""
# print(dic)
# 将字典print出来结果是:{ListNode{val: 1, next: ListNode{val: 2, next: None}}: 1, ListNode{val: 2, next: None}: 1}
"""
return False
注意:字典的键,也可以是链表的一个节点,并不局限于数字和字符。
# print(dic)
# 将字典print出来结果是:
{ListNode{val: 1, next: ListNode{val: 2, next: None}}: 1, ListNode{val: 2, next: None}: 1}
方法二:快慢指针
此方法空间复杂度为O(1)。
当有环存在时,快指针总会追上慢指针。
可参考leetcode大神的解法:相爱相杀好基友——数组与链表。文中讲了多种快慢指针的应用,比如:获取倒数第k个元素,获取中间位置的元素,判断链表是否存在环,判断环的长度等和长度与位置有关的问题。
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def hasCycle(self, head):
"""
:type head: ListNode
:rtype: bool
"""
# 若head为空,直接返回false
if head == None:
return False
# 定义快慢指针
slowp = head
fastp = head.next
# 当快指针为None时,证明没有环退出循环返回false
while fastp:
# 当快慢指针相等时,证明有环存在
if fastp == slowp:
return True
# 慢指针每次移动1,快指针每次移动2
slowp = slowp.next
fastp = fastp.next
# 当快指针不为链表末尾时,快指针移动2;当快指针为链表末尾时(fastp.next为None),仅移动1
if fastp:
fastp = fastp.next
return False
知识点
- 字典的键,也可以是链表的一个节点,并不局限于数字和字符,具体参考方法一。
- 快慢指针有很多应用,参考方法二介绍。