LeetCode ยท #141

Linked List Cycle Solution

Given head, determine if the linked list has a cycle.

01
Section One ยท Problem

Problem Statement

๐Ÿท๏ธ

Difficulty

Easy

๐Ÿ”—

LeetCode

Problem #141

๐Ÿ—๏ธ

Pattern

Fast-Slow Pointers โ€” Floyd's algorithm

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.
MetricValue
TimeO(n)
SpaceO(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 โ‰  null and fast.next โ‰  null:
  • slow = slow.next (1 step)
  • fast = fast.next.next (2 steps)
  • If slow == fast โ†’ return true.
  • 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
LINKED LIST: 3 โ†’ 2 โ†’ 0 โ†’ -4 โ†’ (back to 2) 3 2 0 -4 cycle SLOW (ร—1) vs FAST (ร—2) โ€” step-by-step Step 0: slow = 3, fast = 3 both start at head Step 1: slow = 2 (+1), fast = 0 (+2) โ‰  continue Step 2: slow = 0 (+1), fast = 2 (+2, looped: -4โ†’2) โ‰  continue Step 3: slow = -4, fast = -4 โ˜… MATCH! slow == fast โ†’ cycle detected! They met inside the cycle. Answer: true โœ“
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

ApproachTimeSpaceTrade-off
HashSetO(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

CaseInputWhy It Matters
Empty listnullfast is null โ†’ loop doesn't execute โ†’ false.
Single node, no cycle1 โ†’ nullfast.next is null โ†’ false.
Single node, self-cycle1 โ†’ 1slow=1, fast=1's next is itself โ†’ both advance to 1 โ†’ true.
Cycle at tail1โ†’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.

โ† Back to Linked List problems