The intuitive idea is to use extra memory space to record the visited node, which can be done by a set or array, and check them while visitng new node, if the new node is visited, then return the node, which will be the beginning node of the cycle.
# 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
"""
lst = []
curr = head
while curr:
if curr not in lst:
lst.append(curr)
elif curr in lst:
break
curr = curr.next
return curr
However, if it would cause high time complexity and memory complexity as you need to check the data structure everytime when you visit a new node. And the space complexity will be O(n).
The following code is using Floyd's cycle detection algorithm.
# 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
"""
slow = head
fast = head
while fast:
fast = fast.next
if fast == None:
return fast
else:
fast = fast.next
slow = slow.next
if fast == slow:
slow = head
break
if fast == None:
return fast
while fast != slow:
fast = fast.next
slow = slow.next
return fast
logic:
fast pointer go two steps each time while slow pointer go one step each time.
Thus: Distance F = Distance S
if there is a cycle, assume Distance M is from head to the beginning node of the cycle, L is the length of the cycle, K is the steps that taken from the cycle beginning node to the F、S coincidence point.
so,
D_s = m+k
D_f = m+k+n(l)
as Distance F = Distance S
m+k+n(l) = 2(m+k)
m+k = n*L
thus, fast go m steps will always reach to the beginng node of the cycle, as the fast pointer is already taken K steps.