给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
解答:
# 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
"""
fast = slow = head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
if slow == fast:
return True
return False
总结:
思路:设置两个指针slow和fast,一个步长为1,一个步长为2进行遍历。如果有环,则slow和fast总会在某一点相遇。如果没有环,则fast会先为空,或者fast.next为空。
关于环形链表问题的总结:
1、快慢指针一直到相遇时的循环次数等于环的长度。(可推导)
Case1:一个完美的环状链表,即链表头尾相连
一个环形链表:{A,B,C,A,B,C,……}
其上存在两个指针,A指针移动速度是B指针的两倍。
A,B同时从节点1出发,所经过的节点如下:
快指针A:A->C->B->A
慢指针B:A->B->C->A
A、B指针在节点A第一次相遇,循环次数为3,而环的程度正好也为3。那这个是不是巧合呢?
首先我们要理解的是循环的次数代表的是什么。
- 每次循环,对于B这个慢指针来说,意味着走了一个单位长度。
- 而对于A来说,走了两个单位长度。
- 那么二者第一次相遇必然是在A走了2圈,B走了1圈的时候。
- 假如A的速度是B的3倍,那么二者第一次相遇是在A走了3圈,B走了1圈的时候。
- 同理A是B的5倍速度,相遇时A走了5圈,B走了1圈
…
n. A的速度是B的n倍,相遇时A走了n圈,B走了1圈
从上面的观察我们可以发现,无论A的速度是B的几倍,两者第一次相遇必然是在B走了1圈时。
因为B的速度代表的是链表基本的长度单位,即从一个节点移动到下一个节点的距离。
同时在链表中,每个节点与节点之间这个距离是不变的。
当循环结束时,B走了1圈,正好是环的长度。而B每次移动一个单位距离,因此环的长度等于循环次数。
Case2:不完美的环状链表,即,链表中某一中间节点与尾部相连
一个环形链表(如图所示):{D,E,A,B,C,A,B,C,……}
其上存在两个指针,A指针移动速度是B指针的两倍。
A,B同时从节点1出发,所经过的节点如下:
快指针A:D->A->C->B
慢指针B:D->E->A->B
根据上图,我们可以计算出A、B行走的距离:
A = d+e+a+b+c+a
B = d+e+a
因为A的速度是B的2倍,那么A行走的距离也因该是B的2倍:
d+e+a+b+c+a = 2(d+e+a)
a+b+c = d+e+a
从上图可以看出,a+b+c正好是环的长度,而d+e+a则是B行进的距离。
又知,每次循环B移动一个单位距离,因此在不完美的环状表中,循环次数亦是等于环的长度。
2、快慢指针相遇点到环入口的距离 = 链表起始点到环入口的距离。(可推导)
根据上文公式,我们可以继续推导,即:
a+b+c = d+e+a
b+c = d+e
b+c是相遇点到环入口的距离
d+e是链表起点到环入口的距离
相关问题:
- 判断是否为环形链表
思路:使用追赶的方法,设定两个指针slow、fast,从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fast遇到NULL退出。 - 若为环形链表,求环入口点
思路:快慢指针相遇点到环入口的距离 = 链表起始点到环入口的距离 - 求环的长度
思路:记录下相遇点p,slow、fast从该点开始,再次碰撞所走过的操作数就是环的长度s - 判断两个链表是不是相交(思路:如果两个链表相交,那么这两个链表的尾节点一定相同。直接判断尾节点是否相同即可。这里把这道题放在环形链表,因为环形链表可以拆成Y字的两个链表。)
转载网址:https://blog.csdn.net/qq_34364995/article/details/80518191