题目:如果一个链表中包含环,如何找出环的入口节点?例如,在如|图3.8所示的链表中,环的入口节点是节点3。
思路:解决这个问题的第一步是如何确定一个链表中包含环。受到面试题22的启发,我们可以用两个指针来解决这个问题。和前面的问题一样,定义两个指针,同时从链表的头节点出发,一个指针一次走一步,另一个指针一次走两步。如果走得快的指针追上了走得慢的指针,(相遇时)那么链表就包含环;如果走得快的指针走到了链表的末尾(m pNext指向NULL)都没有追上第一个指针,那么链表就不包含环。
第二步是如何找到环的入口。我们还是可以用两个指针来解决这个问题。先定义两个指针P1和P2指向链表的头节点。如果链表中的环有n个节点,则指针P1先在链表上向前移动n步,然后两个指针以相同的速度向前移动。当第二个指针指向环的入口节点时,第一个指针已经围绕着环走了一圈,又回到了入口节点。
剩下的问题是如何得到环中节点的数目。我们在前面提到判断一个链表里是否有环时用到了一快一慢两个指针。如果两个指针相遇,则表明链表中存在环。两个指针相遇的节点一定是在环中。可以从这个节点出发,一边继续向前移动一边计数,当再次回到这个节点时,就可以得到环中节点数了。
但是,这种时间复杂度高。
最好:两个指针一个fast、一个slow同时从一个链表的头部出发,
fast一次走2步,slow一次走一步,如果该链表有环,两个指针必然在环内相遇,
此时只需要把其中的一个指针重新指向链表头部,另一个不变(还在环内),
这次两个指针一次走一步,相遇的地方就是入口节点。
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def EntryNodeOfLoop(self, pHead):
if pHead==None or pHead.next==None or pHead.next.next==None:
return None
low=pHead.next
fast=pHead.next.next
while low!=fast:
if fast.next==None or fast.next.next==None:
return None
low=low.next
fast=fast.next.next
fast=pHead
while low!=fast:
low=low.next
fast=fast.next
return fast
另一种思路: 增加空间复杂度
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def EntryNodeOfLoop(self, pHead):
# write code here
#遍历链表,环的存在,遍历遇见的第一个重复的即为入口节点
tempList = []
p = pHead
while p:
if p in tempList:
return p
else:
tempList.append(p)
p = p.next