Linked List · 3 of 36
Write a program to Detect loop in a linked list
Find out if a chain of boxes secretly bends back into a circle, by sending a slow runner and a fast runner and seeing if they ever meet.
- Simple way
- time O(n)
room O(n) - Clever way
- time O(n)
room O(1)
The problem, simply
You get the head of a linked list. Normally, if you keep following the next arrows, you reach null and stop. But in a broken chain, the last box may point back to some earlier box, and then you would walk in circles forever.
Say true if the chain has such a loop and false if it ends in null. You do not know the length of the chain, and you cannot mark the boxes.
A story to remember it
Picture it
Six boxes. The last box, 8, points back to box 2, so the chain never reaches null. The boxes from 2 to 8 form the loop.
- path
Examples
A loop in the middle
- In
5 -> 9 -> 2 -> 7 -> 4 -> 8 -> back to 2- Out
true
After 8 the chain goes back to 2 and repeats 2, 7, 4, 8 forever.
No loop
- In
1 -> 2 -> 3 -> 4 -> null- Out
false
The fast runner reaches the end and stops.
The whole chain is a ring
- In
1 -> 2 -> back to 1- Out
true
The loop starts at the head.
One box pointing to itself
- In
7 -> back to 7- Out
true
The smallest possible loop.
One box or empty, no loop
- In
7 -> null- Out
false
fast.next is null right away.
Way 1: the simple way
Keep a guest book of every box you have stepped on, a hash set. If you step on a box that is already in the book, you have been here before, so there is a loop. If you reach null, there is none.
Store the box itself, not its number. Two different boxes can hold the same number.
The walker has stepped on 5, 9, 2, 7, 4 and 8. The next step lands on box 2 again, which is already in the book.
- seen
- rejected
import java.util.*;
class Solution {
public boolean hasCycle(ListNode head) {
Set<ListNode> seen = new HashSet<>(); // the boxes themselves
for (ListNode cur = head; cur != null; cur = cur.next) {
if (!seen.add(cur)) return true; // already stepped here
}
return false; // reached null
}
}How long it takes: each box is stepped on once before the repeat, O(n). Extra room: the book holds every box, O(n).
Way 2: the clever way
Two runners: slow moves one box at a time, fast moves two.
- Both start at the head.
- While
fastandfast.nextare notnull, moveslowone step andfasttwo steps. - If they land on the same box, there is a loop. Say
true. - If
fastreaches the end, there is no loop. Sayfalse.
Why they must meet: once both are inside the loop, every turn fast gains exactly one box on slow. A gap that shrinks by one each turn must reach zero; fast cannot jump over slow.
The sprinter catches the jogger on the loop
01 / 05
Both runners start on the head, 5.
- turn
- 0
- looking now
- checking
- answer
On a chain without a loop, like 1 -> 2 -> 3 -> 4, fast goes 1, 3, then fast.next.next is null, the loop test fails, and the answer is false.
class Solution {
public boolean hasCycle(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next; // jog one box
fast = fast.next.next; // sprint two boxes
if (slow == fast) return true;
}
return false; // fast fell off the end
}
}How long it takes: before the loop, slow walks at most n boxes; on the loop, fast closes the gap in at most one lap. So O(n). Extra room: two fingers, O(1).
Watch out for
- Test
fast != null && fast.next != nullin that order. Readingfast.next.nextwhenfast.nextisnullcrashes. - Compare boxes with
==, not their numbers. Two different boxes can hold the same number without any loop. - A fast runner moving 3 boxes a turn also works on most loops, but the "gap shrinks by one" proof needs a speed difference of exactly one.
What interviewers ask next
- Where does the loop start? After they meet, put one finger back on the head and move both fingers one box at a time. They meet at the first box of the loop. If the path before the loop has
mboxes, walkingmboxes forward from the meeting box (going around the loop) lands exactly on the loop start. - How long is the loop? From the meeting box, walk until you are back, counting steps.
- Remove the loop? Find the start, then find the box whose
nextis the start, and set itsnexttonull. - Why can't the hare jump over the tortoise? Each turn the gap changes by exactly one, from
dtod - 1, so it must hit zero. - Where else does this show up? Finding a duplicate number in an array of
n + 1values from 1 ton(LeetCode 287), and checking for "happy numbers": both are hidden loops.
Remember this
Grown-up words: the loop is a cycle, the runners are slow and fast pointers, the whole method is Floyd's cycle detection (the tortoise and the hare), and the guest book is a hash set of nodes.