题目描述
Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.
Note: Do not modify the linked list.
Example:
Input: head = [3,2,0,-4], pos = 1
Output: tail connects to node index 1
Explanation: There is a cycle in the linked list, where tail connects to the second node.
解题思路
这道题不难的,按照《剑指Offer》P140——P141上介绍的方法,主要的思路是:找到一快一慢两个指针相遇的节点 -> 计算环中节点数目 -> 找到环的入口节点,写出来的python代码如下:
def MeetingNode(root):
if root == None:
return None
pSlow = root.next
if pSlow == None:
return None
pFast = pSlow.next
while pFast != None and pSlow != None:
if pFast == pSlow:
return pFast
pSlow = pSlow.next
pFast = pFast.next
if pFast != None:
pFast = pFast.next
return None
def EntryNodeOfLoop(root):
meetingNode = MeetingNode(root)
if meetingNode == None:
return None
nodesInLoop = 1
pNode1 = meetingNode
while pNode1.next != meetingNode:
pNode1 = pNode1.next
nodesInLoop += 1
pNode1 = root
for i in range(nodesInLoop):
pNode1 = pNode1.next
pNode2 = root
while pNode1 != pNode2:
pNode1 = pNode1.next
pNode2 = pNode2.next
return pNode1
然而事情并没有那么顺利,在LeetCode上测试时间复杂度超出了限制,于是参考了一下别人的代码,优化后的代码如下:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if head == None or head.next == None or head.next.next == None:
return None
else:
pSlow = head.next
pFast = pSlow.next
while pFast != pSlow and pFast and pFast.next:
pSlow = pSlow.next
pFast = pFast.next.next
if pFast == pSlow:
pSlow = head
while pSlow != pFast:
pFast = pFast.next
pSlow = pSlow.next
return pSlow
return None
主要做的优化有两处:
1、在判断一快一慢指针相遇的节点时,尽量减少多次 if 判断。此外,在第一个while循环中不需要再判断pSlow了,因为pSlow相当于上一步的pFast,已经判断过其是否为None了。
2、不需要计算环中的节点数,因为计算节点数的方法是让pNode1走到相遇节点处,计算走了多少步即为节点数N;然后再让pNode1从头节点走N步,再让pNode2从头节点跟pNode1一起走,实际上直接让pNode1在相遇节点处和pNode2一起走就可以了。
3、为了减少空间复杂度,不需要再重新定义pNode1和pNode2了,因为最后判断相遇节点时,pSlow和pFast都在相遇节点处,保持pFast位置不变,pSlow回到头节点,再让二者一起走即可。