Framework Thinking - Neetcode 150 - Linked List Cycle Detection
Here is solutions for Linked List Cycle Detection
1. Understand the Problem
-
Given the head of a singly linked list, determine if the list contains a cycle.
-
A cycle exists if some node’s next pointer points back to a previous node in the list.
2. Clarify Constraints & Ask Questions
- Can the input be empty (head = None)?
=> Yes, return False (no cycle).
- What is the expected output?
=> Boolean (True if a cycle exists, otherwise False).
- Can the linked list contain only one node?
=> Yes. If the node points to itself (next = head), it’s a cycle.
- Are there any restrictions on modifying the list?
=> Usually, we should avoid modifying the list.
- What is the expected time and space complexity?
=> Ideally Time: O(n) and Space: O(1).
3. Explore Examples
| Linked List | Cycle | Output |
|---|---|---|
1 → 2 → 3 → None |
No | False |
1 → 2 → 3 → 1 (back to 1) |
Yes | True |
1 → None |
No | False |
1 → 1 (self-loop) |
Yes | True |
4. Brainstorm 2 - 3 Solutions
4.1. Solution 1: Use a Hash Set (Naive)
-
Traverse list, store visited nodes.
-
If we encounter a visited node → cycle detected.
-
Time: O(N).
-
Space: O(N).
4.2. Solution 2: Floyd’s Cycle Detection (Optimized) – “Tortoise and Hare”
Use two pointers:
- slow moves 1 step at a time
- fast moves 2 steps at a time
-
If they ever meet → cycle exists
-
If fast or fast.next = None → no cycle
-
Time: O(N).
-
Space: O(N).
-
Idea: A fast and a slow start in the same start, and it will meet each other definately.
5. Implement solutions
5.1. Hash Set
Idea: Because 1 node can have only 1 next => So a node point to null, or point to another node.
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
seen = set()
cur = head
while cur:
if cur in seen:
return True
seen.add(cur)
cur = cur.next
return False
-
Time: O(N).
-
Space: O(N).
5.2. Fast And Slow Pointers
Idea: The fast and slow pointer start with the same point will always meet each others.
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
slow, fast = head, head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return False
-
Time: O(N).
-
Space: O(1).
6. Dry run examples
1 → 2 → 3 → 4 → 5
↑ ↓
← ← ←
| Step | slow | fast | Notes |
|---|---|---|---|
| Init | 1 | 1 | Both start at head |
| 1 | 2 | 3 | slow=1→2, fast=1→2→3 |
| 2 | 3 | 5 | slow=2→3, fast=3→4→5 |
| 3 | 4 | 4 | slow=3→4, fast=5→4→ 🎯 meet here! |