Arrays · Core Array Techniques

Cyclic Sequence Detection

Treating an array as a function i -> nums[i] and using Floyd's tortoise-and-hare to find a cycle - and the value where it starts - in O(1) space.

  • 6 min read
  • 11 practice questions
  • 2 graded problems
On this page
  1. Description
  2. The approach
  3. Where you'll see it
  4. Which tool for which job?
  5. Common mistakes
  6. Check yourself
  7. Key takeaways
  8. Quick revise
  9. Practice

Description

Cyclic sequence detection finds a loop in a sequence where each value decides the next one. That can be a linked list's next pointers, or an array read as "go to index nums[i]". Floyd's tortoise and hare does it with two pointers moving at different speeds and O(1) extra memory. They must meet inside the loop, and a second walk finds where the loop starts. That's how Find the Duplicate Number and Linked List Cycle II are solved without a hash set.

We'll go from simple to more technical:

  1. The pattern: phase 1 finds a meeting point, phase 2 finds the entrance.
  2. Where state-to-next-state loops show up in production.
  3. The mistakes: stopping at phase 1, and reaching for a set by reflex.
  4. When the O(1) space is worth the less obvious code.

The approach

The obvious way to find a repeat is to remember every value you've visited in a hash set. That's O(n) time, but also O(n) extra memory. Floyd's method uses two pointers instead. The slow one moves one step at a time, and the fast one two steps. Once both are inside the loop, the fast one gains one step per move, so it must catch the slow one.

Take nums = [2, 5, 1, 4, 3, 4] and read each value as the next index to visit. Starting at index 0, the walk goes 0, 2, 1, 5, then enters a loop between 4 and 3:

index 0

index 2

index 1

index 5

index 4

index 3

index 0

index 2

index 1

index 5

index 4

index 3

Index 4 is where the loop starts. Two indexes point to it, 5 and 3, so 4 is the value that appears twice. The two phases find it:

PhaseslowfastNote
122both start at nums[0]
115
153
143
133they meet inside the loop
223slow restarts at nums[0]; now both move one step
214
253
244they meet at the entrance: the duplicate is 4

Java

int slow = nums[0], fast = nums[0];
do {
    slow = nums[slow];
    fast = nums[nums[fast]];
} while (slow != fast);          // phase 1: they meet somewhere inside the cycle

slow = nums[0];
while (slow != fast) {            // phase 2: distance from start to cycle entrance
    slow = nums[slow];            // equals distance from meeting point to cycle entrance
    fast = nums[fast];
}
return slow;                      // the cycle's entrance

Python

slow = fast = nums[0]
while True:                    # phase 1: they meet somewhere inside the cycle
    slow = nums[slow]
    fast = nums[nums[fast]]
    if slow == fast:
        break

slow = nums[0]
while slow != fast:            # phase 2: distance from start to cycle entrance
    slow = nums[slow]          # equals distance from meeting point to cycle entrance
    fast = nums[fast]
# slow is the cycle's entrance

This is the same algorithm as cycle detection in a linked list: nums[i] plays the role of node.next. Why is the entrance the duplicate? Any walk over a finite set of indexes must loop eventually. No value is 0, so nothing points back to index 0, and the walk starts on a tail outside the loop. The node where the tail joins the loop is pointed to from the tail and from inside the loop. So its index appears twice as a value.

Where you'll see it

Any system that moves from one state to the next by a fixed rule can loop. An ID-remapping table that maps back onto itself is one example. With a limited number of states, a loop is guaranteed sooner or later, and this walk finds it without storing every state you've visited.

Which tool for which job?

You needUse
Does the sequence loop? (memory is fine)a hash set of visited states
Does it loop? in O(1) spaceFloyd: slow and fast pointers
Where the loop startsFloyd phase 2: one pointer from the start, one from the meeting point
The loop's lengthfrom the meeting point, walk until you're back
Fewer calls to an expensive next functionBrent's algorithm
A duplicate in n + 1 values from 1..n, read-onlytreat values as next pointers; the entrance is the duplicate

Common mistakes

MistakeWhat happensDo this instead
Returning the phase-1 meeting pointa point in the loop, not its entrancerun phase 2
Moving both pointers two steps in phase 2they may never meet at the entranceone step each in phase 2
Not checking fast and fast.next for nulla crash on lists without a cyclecheck both before advancing
Starting fast at a different place than phase 2 assumesphase 2 lands off the entrancestart both at the head (or both one step in)
Sorting or marking the array to find the duplicatethe input is changedFloyd leaves it untouched

Check yourself

Try to answer before opening each one - recalling beats re-reading.

1. A solution finds the repeated value with a hash set of visited values. Is it wrong?

Show answer

No. It finds the duplicate correctly, using O(n) extra memory. Floyd's method finds the same answer in O(1) memory, and that saving is the whole reason to use it.

2. Is the point where the pointers meet in phase 1 the loop's entrance?

Show answer

Not necessarily. It's somewhere inside the loop. In the example they met at 3, but the entrance is 4. Phase 2 finds the entrance: restart one pointer and move both one step at a time.

3. Why must n + 1 values, each between 1 and n, contain a duplicate?

Show answer

There are n + 1 values but only n possible ones, so at least one value must repeat. This is the pigeonhole principle. You don't need to scan to know a duplicate exists, only to find which one it is.

Key takeaways

  • An array whose values are valid indexes can be walked like a linked list. Floyd's method finds its loop in O(1) extra memory.
  • Phase 1 only finds a meeting point somewhere in the loop. Phase 2 finds the entrance.
  • With n + 1 values in a range of n, a duplicate must exist.
  • The same two phases work for a linked list's next pointers and for array values read as indexes.

Quick revise

The whole skill on one page, for the night before an interview.

Everything from the lesson and the deep dive on one page. Skim it before practice or an interview, and open the full lesson for anything that doesn't ring a bell.

Pick the tool

You needUse
Loop or not, memory is finea hash set
Loop or not, O(1) spaceFloyd phase 1
Where the loop startsFloyd phase 2
Loop lengthwalk from the meeting point back to itself
Fewer next() callsBrent's algorithm

Snippets worth knowing by heart

Java

int slow = nums[0], fast = nums[nums[0]];
while (slow != fast) { slow = nums[slow]; fast = nums[nums[fast]]; }   // phase 1: meet in the loop
slow = 0;
while (slow != fast) { slow = nums[slow]; fast = nums[fast]; }         // phase 2: one step each
return slow;                                                           // the entrance = the duplicate

Python

slow, fast = head, head
while fast and fast.next:
    slow, fast = slow.next, fast.next.next
    if slow is fast:                    # phase 1: they met in the loop
        slow = head
        while slow is not fast:         # phase 2: one step each
            slow, fast = slow.next, fast.next
        return slow                     # the entrance
return None                             # no loop

The traps

  • Returning the meeting point: it's somewhere in the loop, not the entrance. Run phase 2.
  • Two steps in phase 2: the pointers may never meet at the entrance. Move both one step at a time.
  • No null checks: a list without a cycle crashes. Check fast and fast.next before advancing.
  • Mismatched starts: phase 2 lands off the entrance. Start both pointers at the head.
  • Mutating the input: sorting or marking the array changes it. Floyd finds the duplicate without touching it.

Staff-level points, one line each

  • They meet within L steps of both being in the loop: the gap shrinks by one per step.
  • a + b = kL, so a = kL - b - phase 2 meets at the entrance.
  • [1, 3, 1, 2]: met at 2; the duplicate is 1.
  • Brent: 4,625 calls of f vs Floyd's 6,290 for the same loop.
  • Any function on a finite set loops: PRNG periods, happy numbers, Pollard's rho.

Say it in an interview

  • "Fast gains one step per move, so inside the loop it must catch slow."
  • "The meeting point is in the loop; phase 2 finds the entrance."
  • "It's O(n) time and O(1) space, and it doesn't modify the array."
  • "If memory didn't matter, a visited set would be simpler."

Practice

This skill comes with 11 multiple-choice questions that tell you which misconception a wrong answer reveals and 2 graded problems. Your answers are graded and your mastery is tracked, so you'll know when the skill holds up. Running code and saving progress need a free account.

Practice Cyclic Sequence Detection free

Find the Duplicate Number

MediumProCoding problemJava · Python

nums holds n + 1 numbers, each between 1 and n, so at least one value has to repeat. In every test exactly one value repeats (it may appear more than twice). Return it.

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Linked List Cycle II

MediumProCoding problemJava · Python

A singly linked list may loop back on itself: instead of ending in null, the last node's next points at an earlier node. Find the node where the loop begins.

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Practice Cyclic Sequence Detection free

No card needed. Lessons, practice questions and easy problems are free forever.

Free plan, no card · 7-day Pro trial · Cancel anytime