LeetCode ยท #141
Linked List Cycle Solution
Given head, determine if the linked list has a cycle.
01
Section One ยท Problem
Problem Statement
Given head, return true if there is a cycle in the linked list โ i.e., some node can be reached again by continuously following next. Otherwise return false.
Example
Input: 3 โ 2 โ 0 โ -4 โ (back to 2)
Output: true // Tail connects to node at index 1
Constraints
โข 0 โค number of nodes โค 10โด โข -10โต โค Node.val โค 10โต
02
Section Two ยท Approach 1
HashSet โ O(n) space
Traverse the list, storing each visited node in a HashSet. If you encounter a node already in the set, there's a cycle. If you reach null, no cycle.
Problem: O(n) extra space for the set. Floyd's cycle detection uses two pointers with O(1) space โ no set needed.
| Metric | Value |
|---|---|
| Time | O(n) |
| Space | O(n) |
03
Section Three ยท Approach 2
Floyd's Tortoise & Hare โ O(1) space
Use two pointers: slow moves 1 step at a time, fast moves 2 steps. If there's a cycle, fast will eventually lap slow and they'll meet. If fast reaches null, no cycle.
๐ก Mental model: Two runners on a circular track. The fast runner laps the slow runner โ guaranteed. On a straight track (no loop), the fast runner reaches the end first. If the slow and fast pointers ever point to the same node, you've confirmed a loop.
Algorithm
- Step 1:
slow = head,fast = head. - Step 2: While
fast โ nullandfast.next โ null: slow = slow.next(1 step)fast = fast.next.next(2 steps)- If
slow == fastโ returntrue. - Step 3: Return
false.
๐ฏ Why they must meet:
- Once fast enters the cycle, the gap between fast and slow decreases by 1 each step (fast gains 1 step per iteration).
- Eventually the gap becomes 0 โ they collide. This takes at most one full cycle length of iterations.
04
Section Four ยท Trace
Visual Walkthrough
Trace: 3 โ 2 โ 0 โ -4 โ (back to 2):
Floyd's Cycle Detection โ slow vs fast pointer
05
Section Five ยท Implementation
Code โ Java & Python
Java โ Floyd's Algorithm
class Solution {
public boolean hasCycle(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) return true;
}
return false;
}
}
Python โ Floyd's Algorithm
class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast: return True return False
06
Section Six ยท Analysis
Complexity Analysis
| Approach | Time | Space | Trade-off |
|---|---|---|---|
| HashSet | O(n) | O(n) | Simple but uses extra memory |
| Floyd's โ optimal | O(n) | O(1) | Two pointers, no extra storage |
07
Section Seven ยท Edge Cases
Edge Cases & Pitfalls
| Case | Input | Why It Matters |
|---|---|---|
| Empty list | null | fast is null โ loop doesn't execute โ false. |
| Single node, no cycle | 1 โ null | fast.next is null โ false. |
| Single node, self-cycle | 1 โ 1 | slow=1, fast=1's next is itself โ both advance to 1 โ true. |
| Cycle at tail | 1โ2โ3โ(back to 3) | Self-loop at last node. Fast enters cycle, laps slow. |
โ Common Mistake: Checking
fast.next without first checking fast != null. If fast reaches null (no cycle), accessing fast.next throws a NullPointerException. Always check both: fast != null && fast.next != null.