Skip to content

Linked List Cycle

Given 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.

InputOutputExplanation
Head: [3,2,0,-4], pos: 1trueCycle: 2 → 0 → -4 → 2
Head: [1,2], pos: 0trueCycle: 2 → 1 → 2
Head: [1], pos: -1falseNo cycle
  • The number of the nodes in the list is in the range [0, 10^4].
  • -10^5 <= Node.val <= 10^5
  • pos is -1 or a valid index in the linked-list.
ApproachTimeSpaceBest When
Floyd’s AlgorithmO(n)O(1)Space is limited; elegant two-pointer technique
Hash SetO(n)O(n)Space is available; easier to understand
  • Learn Floyd’s Algorithm first — it is the optimal solution and a classic interview technique.
  • Use Hash Set as a fallback if you forget the two-pointer logic; it is straightforward and correct.
Space Efficient & Optimal
Floyd’s Algorithm
O(n) time · O(1) space
Easy to Implement
Hash Set
O(n) time · O(n) space

Approach 1: Floyd’s Algorithm (Tortoise & Hare)

Section titled “Approach 1: Floyd’s Algorithm (Tortoise & Hare)”
★ Recommended

Use two pointers starting at the head: a slow pointer that advances one step at a time, and a fast pointer that advances two steps at a time. If a cycle exists, the fast pointer will eventually catch up to (meet) the slow pointer. If no cycle exists, the fast pointer will reach the end (null).

⏱ Time O(n) Single pass with two pointers 💾 Space O(1) Only two pointer variables

Input: [3, 2, 0, -4] with cycle at index 1

StepSlow PositionFast PositionNotes
Start33Both start at head
Step 120Slow moves 1, fast moves 2
Step 202Slow moves 1, fast moves 2
Step 3-4-4Slow moves 1, fast moves 2
Step 420Both in cycle, continue
Step 50-4Fast closing in
Step 6-42Still moving
Step 720Pointers converge
Step 80-4Slow == Fast → Cycle detected!

Animated walkthrough

How the tortoise and hare detect a cycle

Use Next or Autoplay to see the slow (tortoise) and fast (hare) pointers move through the list. When they meet, a cycle is confirmed.

Step 1 of 7
Waiting to begin...
Array state
Memory / lookup state

function hasCycle(head):
if head is null or head.next is null:
return false
slow = head
fast = head
while fast is not null and fast.next is not null:
slow = slow.next // Move 1 step
fast = fast.next.next // Move 2 steps
if slow == fast:
return true // Collision detected
return false // No cycle found
linked_list_cycle_floyd.py
from typing import Optional
class ListNode:
def __init__(self, x: int):
self.val = x
self.next: Optional['ListNode'] = None
def hasCycle(head: Optional[ListNode]) -> bool:
if not head or not head.next:
return False
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return False
# Test cases
if __name__ == "__main__":
# Test case 1: Cycle exists
node1 = ListNode(3)
node2 = ListNode(2)
node3 = ListNode(0)
node4 = ListNode(-4)
node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node2 # Cycle
print(f"Cycle exists: {hasCycle(node1)}") # True
# Test case 2: No cycle
node5 = ListNode(1)
node6 = ListNode(2)
node5.next = node6
print(f"Cycle exists: {hasCycle(node5)}") # False
# Test case 3: Single node, no cycle
node7 = ListNode(1)
print(f"Cycle exists: {hasCycle(node7)}") # False
✓ Simple

Iterate through the linked list, storing each visited node in a set. If we encounter a node that is already in the set, a cycle exists. If we reach the end of the list (null), there is no cycle.

⏱ Time O(n) Single pass through list 💾 Space O(n) Set grows with visited nodes

Input: [3, 2, 0, -4] with cycle at index 1

NodeIn Set?Action
3NoAdd to set → {3}
2NoAdd to set → {3, 2}
0NoAdd to set → {3, 2, 0}
-4NoAdd to set → {3, 2, 0, -4}
2YesCycle detected! Return true
function hasCycle(head):
seen = empty set
current = head
while current is not null:
if current is in seen:
return true // Found a cycle
seen.add(current)
current = current.next
return false // No cycle found
linked_list_cycle_hash_set.py
from typing import Optional
class ListNode:
def __init__(self, x: int):
self.val = x
self.next: Optional['ListNode'] = None
def hasCycle(head: Optional[ListNode]) -> bool:
seen = set()
current = head
while current:
if current in seen:
return True
seen.add(current)
current = current.next
return False
# Test cases
if __name__ == "__main__":
# Test case 1: Cycle exists
node1 = ListNode(3)
node2 = ListNode(2)
node3 = ListNode(0)
node4 = ListNode(-4)
node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node2 # Cycle
print(f"Cycle exists: {hasCycle(node1)}") # True
# Test case 2: No cycle
node5 = ListNode(1)
node6 = ListNode(2)
node5.next = node6
print(f"Cycle exists: {hasCycle(node5)}") # False
# Test case 3: Single node, no cycle
node7 = ListNode(1)
print(f"Cycle exists: {hasCycle(node7)}") # False
✓ Simple

A third approach demonstrating an alternative technique for solving this problem. This implementation optimizes either time or space complexity compared to the previous approaches.

⏱ Time O(n) Optimized complexity 💾 Space O(1) Efficient space usage
function approach3():
// Implementation approach goes here
linked_list_cycle_optimized.py
"""
Solution for Linked List Cycle
"""
def solve():
"""Implementation for approach 3 of Linked List Cycle"""
pass
if __name__ == "__main__":
print("Solution ready")