Linked List Cycle easy
Problem Statement
Given head
, the head of a linked list, determine if the linked list has a cycle in it.
There is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the next
pointer. Internally, pos
is used to denote the index of the node that tail's next
pointer is connected to. Note that pos
is not passed as a parameter.
Return true
if there is a cycle in the linked list. Otherwise, return false
.
Example 1:
Input: head = [3,2,0,-4], pos = 1 Output: true Explanation: There is a cycle in the linked list, where the tail connects to the second node.
Example 2:
Input: head = [1,2], pos = 0 Output: true Explanation: There is a cycle in the linked list, where the tail connects to the first node.
Example 3:
Input: head = [1], pos = -1 Output: false Explanation: There is no cycle in the linked list.
Steps
-
Fast and Slow Pointers: We use two pointers, a
slow
pointer and afast
pointer. Theslow
pointer moves one step at a time, while thefast
pointer moves two steps at a time. -
Cycle Detection: If there is a cycle, the
fast
pointer will eventually lap theslow
pointer. This is because thefast
pointer is gaining one node on theslow
pointer with each iteration. -
No Cycle: If there is no cycle, the
fast
pointer will reach the end of the list (fast
becomesNone
).
Explanation
The algorithm relies on the fact that if a cycle exists, the fast pointer will inevitably catch up to the slow pointer. Imagine the slow pointer as a car traveling at a constant speed, and the fast pointer as a car traveling at twice the speed. If both cars are on a circular track, the faster car will always eventually overtake the slower car.
If there's no cycle, the fast pointer will simply reach the end of the list, indicating no cycle.
Code
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
def hasCycle(head):
"""
:type head: ListNode
:rtype: bool
"""
slow = head
fast = head
while fast and fast.next: #Check for null pointer exceptions
slow = slow.next
fast = fast.next.next
if slow == fast:
return True # Cycle detected
return False # No cycle
#Example Usage
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 #Creating the cycle
print(hasCycle(head)) #Output: True
head2 = ListNode(1)
head2.next = ListNode(2)
print(hasCycle(head2)) #Output: False
Complexity
- Time Complexity: O(N), where N is the number of nodes in the linked list. In the worst case (no cycle), the fast pointer iterates through the entire list.
- Space Complexity: O(1). The algorithm uses only a constant amount of extra space for the
slow
andfast
pointers.