目录
一、题目
给定一个链表,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
进阶:
你能用 O(1)(即,常量)内存解决此问题吗?
二、示例
示例1:
输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。
示例2:
输入:head = [1,2], pos = 0 输出:true 解释:链表中有一个环,其尾部连接到第一个节点。
示例3:
输入:head = [1], pos = -1 输出:false 解释:链表中没有环。
提示:
- 链表中节点的数目范围是
[0, 104]
-105 <= Node.val <= 105
pos
为-1
或者链表中的一个 有效索引
三、思路
1、哈希表:遍历所有的节点,每次遍历一个节点时,判断该节点之前是否被遍历过。
复杂度:
时间复杂度:O(N)
空间复杂度:O(N)
2、(进阶)快慢指针:
首先,定义两个指针,快指针fast,慢指针slow,fast指针每次移动两个节点,slow指针每次移动一个节点。如果量两指针在移动过程中相遇,则链表有环,否则,无环。
那么其中的原理是什么呢?
第一种情况,链表无环,那么fast指针一定先比slow指针移动到链表尾部,并且fast指针始终在slow指针前面(除始发位置),因此两指针一定不会相遇;
第二种情况,链表有环。正如龟兔赛跑一样,假想「乌龟」和「兔子」在链表上移动,「兔子」跑得快,「乌龟」跑得慢。那么「兔子」会先于「乌龟」进入环,并且一直在环内移动。等到「乌龟」进入环时,由于「兔子」的速度快,它一定会在某个时刻与乌龟相遇,即套了「乌龟」若干圈。
复杂度:
时间复杂度:O(N)
空间复杂度:O(1)
四、代码
1、
# Definition for singly-linked list.
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
def hasCycle(self, head: ListNode) -> bool:
s = set()
while (head):
if head in s:
return True
else:
s.add(head)
head = head.next
return False
if __name__ == '__main__':
head = ListNode(3)
head.next = ListNode(2)
head.next.next = ListNode(0)
head.next.next.next = ListNode(4)
head.next.next.next.next = head.next
s = Solution()
ans = s.hasCycle(head)
print(ans)
2、
# Definition for singly-linked list.
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
def hasCycle(self, head: ListNode) -> bool:
fast, slow = head, head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
if fast == slow:
return True
return False
if __name__ == '__main__':
head = ListNode(3)
head.next = ListNode(2)
head.next.next = ListNode(0)
head.next.next.next = ListNode(4)
head.next.next.next.next = head.next
s = Solution()
ans = s.hasCycle(head)
print(ans)