Remove a Loop in a Linked List

Solve this Problem
Medium20–25 min
Topics
Companies
Practice:GFG ↗
Given the head of a singly linked list that may contain a cycle, remove the cycle — without deleting any node — and return the head of the resulting (now normal, terminating) list. This builds directly on Floyd's Cycle Detection: once slow and fast meet inside the cycle, the same distance property that locates the loop's first node can instead locate its last node — the one whose next pointer is the cyclic edge itself. Setting that single pointer to null is enough; no node is copied, moved, or deleted.

Test Case 1:

Input:head = [3, 2, 0, -4], pos = 1
Output:[3, 2, 0, -4]
Explanation:The cyclic edge is removed; every original value remains, now in a normal terminating list.

Test Case 2:

Input:head = [1, 2], pos = 0
Output:[1, 2]
Explanation:The whole list was the cycle — after removal, it's a normal 2-node list.

Test Case 3:

Input:head = [1], pos = -1
Output:[1]
Explanation:No loop to remove — the list is returned unchanged.

Constraints

  • 0 ≤ number of nodes in head ≤ 10⁴
  • -10⁹ ≤ node value ≤ 10⁹
  • A cyclic test list is described as (vals, pos) — the last node's next points back to index pos (0-indexed); pos = -1 means no cycle
  • No node is deleted — only the cyclic edge is unlinked, so the returned list has the same values in the same order
🚀

Try the Dry Run

Don't just read the solution — watch it execute, one step at a time.

🧪Try your own test case
1class Solution {
2 public Node removeLoop(Node head) {
3 if (head == null) {
4 return head;
5 }
6 Node slow = head, fast = head;
7 boolean hasLoop = false;
8 while (fast != null && fast.next != null) {
9 slow = slow.next;
10 fast = fast.next.next;
11 if (slow == fast) {
12 hasLoop = true;
13 break;
14 }
15 }
16 if (!hasLoop) {
17 return head;
18 }
19 if (slow == head) {
20 while (fast.next != slow) {
21 fast = fast.next;
22 }
23 } else {
24 slow = head;
25 while (slow.next != fast.next) {
26 slow = slow.next;
27 fast = fast.next;
28 }
29 }
30 fast.next = null;
31 return head;
32 }
33}
34
1
2
3
4
5
6
7
null
Variables
head1 (node 0)
COMPARE

head is not null, so skip the empty-list base case.

Step 1 / 19

Approach & Solutions

Brute Force — Hash Set to Find the Node Whose Next Repeats, Then Snip

Good

Walk the list while tracking prev (the node right before curr). Add each node to a hash set as it's visited. The moment curr is a node that's already in the set, prev must be the true last node of the cycle — the one whose next pointer creates the loop — so set prev.next to null. Correct, but storing every visited node costs O(n) extra space.

TimeO(n)
SpaceO(n)
1// Node definition used in this problem: 2// class Node { 3// int val; 4// Node next; 5// } 6 7class Solution { 8 public Node removeLoop(Node head) { 9 Set<Node> visited = new HashSet<>(); 10 Node curr = head; 11 Node prev = null; 12 while (curr != null) { 13 if (visited.contains(curr)) { 14 prev.next = null; 15 return head; 16 } 17 visited.add(curr); 18 prev = curr; 19 curr = curr.next; 20 } 21 return head; 22 } 23}

Optimal — Floyd's Algorithm to Locate and Snip the Loop

Optimal

Phase 1: run slow/fast pointers until they meet inside the cycle (or fast reaches the end — no loop). Phase 2: if the meeting point is head itself, walk one pointer all the way around the cycle until its next is the meeting point. Otherwise, reset slow to head and advance both pointers one step at a time until slow.next equals fast.next — at that moment fast is sitting on the true last node of the cycle. Either way, set that node's next to null.

TimeO(n)
SpaceO(1)
1// Node definition used in this problem: 2// class Node { 3// int val; 4// Node next; 5// } 6 7class Solution { 8 public Node removeLoop(Node head) { 9 if (head == null) { 10 return head; 11 } 12 Node slow = head, fast = head; 13 boolean hasLoop = false; 14 while (fast != null && fast.next != null) { 15 slow = slow.next; 16 fast = fast.next.next; 17 if (slow == fast) { 18 hasLoop = true; 19 break; 20 } 21 } 22 if (!hasLoop) { 23 return head; 24 } 25 if (slow == head) { 26 while (fast.next != slow) { 27 fast = fast.next; 28 } 29 } else { 30 slow = head; 31 while (slow.next != fast.next) { 32 slow = slow.next; 33 fast = fast.next; 34 } 35 } 36 fast.next = null; 37 return head; 38 } 39}

Related Problems