Find the Duplicate Number

Treat values as next-pointers; the duplicate is a cycle entrance.

Approach

Reading each index's value as a link forms a linked list with a cycle, because a repeated value points two indices to the same place. Use Floyd's cycle detection to find the meeting point, then a second walk from the start to locate the cycle's entry — the duplicate.

Time complexity

O(n)

Space complexity

O(1)

Common mistake

Sorting or using a set — correct but violates the classic O(1) space / no-mutation constraints this problem targets.

Interactive walkthrough — step through it below, free and without an account

Problem

Given an array of n + 1 integers whose values are all in the range 1 through n, exactly one value appears at least twice. Return that repeated value while leaving the array unchanged and using only constant extra space.

Examples

Input: nums = [1,3,4,2,2]

Output: 2

The values define links 0 → 1 → 3 → 2 → 4 → 2, so the cycle begins at index 2, whose value is the duplicate 2.

Input: nums = [3,1,3,4,2]

Output: 3

The value 3 occurs more than once, so it is the duplicate.

Problem

Problem

Given an array of `n + 1` integers whose values are all in the range `1` through `n`, exactly one value appears at least twice. Return that repeated value while leaving the array unchanged and using only constant extra space.

Problem and Goal

Learning goal: Recognize why this array problem can be solved as a cycle-detection problem.

Core idea There are n + 1 positions but only n possible values. If each position points to the position named by its value, at least two positions point into the same destination. That collision creates a cycle, and the cycle's entrance identifies the duplicated value.

Algorithm plan

  • Start from index 0.
  • Interpret nums[index] as the next index.
  • Use two pointers moving at different speeds to detect a meeting inside the cycle.
  • Restart one pointer at index 0 and move both one step at a time.
  • The second meeting point is the cycle entrance and the answer.

Micro-example For nums = [1,3,4,2,2], the links are 0 → 1 → 3 → 2 → 4 → 2. The repeated value 2 causes the cycle 2 → 4 → 2.

Pitfalls

  • Do not confuse an index with the value stored at that index.
  • The first pointer meeting is not necessarily the duplicate; it is only inside the cycle.
  • Sorting and sets solve the problem differently but violate the intended constraints.

Recap

  • Values act as next-pointers.
  • The duplicate is the cycle entrance.
  • Floyd's method uses O(n) time and O(1) space.

Problem and Goal

Why not sort or use a set?

The straightforward approaches are valid, but sorting mutates the array and a set uses O(n) extra space. The classic solution preserves the array and uses only two integer pointers.

Treat the array as a read-only linked structure.

Key Idea: Values Are Links

Learning goal: Translate the array into a linked list without creating any nodes.

Core idea For every index i, define its successor as next(i) = nums[i]. The array becomes a functional graph: each index has exactly one outgoing edge. Starting at 0, the path must eventually revisit an index because there are finitely many indices. The repeated value is exactly where two incoming paths merge, which becomes the entrance of the resulting cycle.

Key insight

The array is never changed. Reading nums[i] is enough to follow the link from index i.

Data structure model

Array conceptLinked-list interpretation
Index iCurrent node
Value nums[i]next pointer
Repeated value dCycle entrance
slowMoves one link
fastMoves two links

Micro-example 0 → nums[0] = 1, then 1 → nums[1] = 3, then 3 → nums[3] = 2. Continuing gives 2 → 4 → 2, a cycle whose entrance is 2.

Pitfalls

  • The cycle is among indices, even though the returned answer is a value.
  • A repeated value means multiple indices can point to the same node.
  • No auxiliary linked-list objects are needed.

Recap

  • Define next(i) as nums[i].
  • Functional graphs eventually cycle.
  • The duplicate labels the cycle entrance.

Key Idea: Values Are Links

From index `i`, jump to index `nums[i]`; the value is the next node.

`3 → nums[3] = 2`

Floyd's Two-Phase Algorithm

Learning goal: Understand why two pointer walks locate the cycle entrance.

Core idea The first phase uses slow = next(slow) and fast = next(next(fast)). Once both pointers enter the cycle, their relative positions change by one node per iteration, so they must meet. That meeting point gives useful information about the cycle length, but it is not generally the entrance.

Algorithm plan

  1. Set slow and fast to index 0.
  2. Advance slow one link and fast two links until they meet.
  3. Set one pointer back to index 0; keep the other at the meeting point.
  4. Advance both one link at a time.
  5. Return the index where they meet.
Floyd's two phases
  1. Detect a meeting inside the cycle.
  2. Reset slow to 0.
  3. Move slow and fast equally.
  4. Their next meeting is the cycle entrance.

Micro-example In 0 → 1 → 3 → 2 → 4 → 2, the pointers first meet at 4. Resetting one pointer gives 0 → 1 → 3 → 2 and 4 → 2; they meet at 2.

Pitfalls

  • Do not return the first meeting point automatically.
  • The second phase must move both pointers at the same speed.
  • Use while true or an equivalent loop carefully so the initial position is not mistaken for a valid meeting.

Recap

  • Phase one finds any point in the cycle.
  • Phase two converts that meeting into the entrance.
  • Every pointer move is an array read, so the time is linear.

Floyd's Two-Phase Algorithm

ApproachTimeExtra spaceConstraint fit
SortO(n log n)O(1) or O(log n)No: mutates the array
SetO(n)O(n)No: uses linear extra space
Floyd pointersO(n)O(1)Yes: read-only and constant space

Walkthrough: [1,3,4,2,2]

Learning goal: Trace both Floyd phases on one concrete input and connect every move to the array.

Core idea The example has n = 4, so valid values are 1 through 4. Following values from index 0 creates 0 → 1 → 3 → 2 → 4 → 2. The first phase finds an interior meeting, while the reset-and-walk phase identifies the entrance.

Pointer movement

Phaseslow movementfast movementPurpose
DetectionOne linkTwo linksMeet inside cycle
LocationOne linkOne linkMeet at entrance

Micro-example Detection: (slow, fast) moves (0,0) → (1,3) → (3,4) → (2,4) → (4,4). Location: reset slow: (0,4) → (1,2) → (3,4) → (2,2); answer 2.

Why the second walk works

The distance from the start to the entrance matches the distance from the first meeting point around the cycle to that entrance, modulo the cycle length.

Pitfalls

  • In the detection phase, fast reads two links, not two array positions numerically.
  • The displayed node is an index; the answer is the same integer used as the duplicate value.
  • Keep the exact input unchanged throughout the trace.

Recap

  • First meeting: index 4, somewhere inside the cycle.
  • Second meeting: index 2, the cycle entrance.
  • Return 2.

Walkthrough: [1,3,4,2,2]

End-to-end Floyd trace for nums = [1,3,4,2,2]. Nodes are indices and arrows are value-based next-pointers.

Linked list
1 / 9
Start at index 0; values define the arrows.
head →0
slowfast
0
 
1
next 3
·
2
next 4
3
next 2
·
4
next 2

Action: init

Read-only cycle detection begins.Pointers always follow existing array links.
1 / 9

Pitfalls and Edge Cases

Learning goal: Distinguish constraint violations from genuine algorithmic errors.

Core idea Several approaches can find a duplicate, but this problem specifically tests whether we can exploit the structure without mutation or linear memory. A set remembers every value, and sorting groups equal values, yet both bypass the intended cycle interpretation. Floyd's algorithm keeps only pointer indices and performs no writes.

Edge-case checklist

  • Duplicate near the beginning: The cycle may enter immediately after index 0.
  • Duplicate near the end: The tail can be long before the pointers reach the cycle.
  • Multiple occurrences: The same repeated integer may appear more than twice; it still labels one cycle entrance.
  • Smallest input: With n = 1, [1,1] immediately forms a self-loop at index 1.

Common pitfall

Sorting or using a set is correct in a general sense, but it violates the classic O(1) space / no-mutation constraints this problem targets.

Micro-example For [1,1], the links are 0 → 1 → 1. The duplicate is the self-cycle entrance 1.

Pitfalls

  • Returning the first Floyd meeting instead of running phase two.
  • Treating nums[i] as data only rather than as a next index.
  • Accidentally writing into nums while trying to mark visited values.

Recap

  • Preserve the input.
  • Use no visited set.
  • Always complete both pointer phases.

Pitfalls and Edge Cases

Why is a set not the canonical solution here?

Complexity and Wrap-up

Learning goal: State the final algorithm, proof idea, and complexity precisely.

Core idea The array induces a linked-list-like walk with one outgoing link per index. Because a duplicate value creates a shared destination, the walk contains a cycle. Floyd's first phase proves and locates a cycle intersection; the second phase identifies its entrance, which is the duplicate.

Algorithm plan

Code
slow = nums[0]
fast = nums[nums[0]]
while slow != fast:
    slow = nums[slow]
    fast = nums[nums[fast]]

slow = 0
while slow != fast:
    slow = nums[slow]
    fast = nums[fast]
return slow

Micro-example For [1,3,4,2,2], the pointers meet first at 4, then meet again at 2 after resetting slow.

Why it works

Every phase advances through existing links, and the second phase's equal-speed walks are aligned to meet exactly at the cycle entrance.

Pitfalls

  • Time is O(n), not O(n²): each phase traverses only a constant number of paths.
  • Space is O(1): only pointer variables are added.
  • The array remains unchanged from input to return.

Recap

  • Model nums[i] as next(i).
  • Detect a cycle, then locate its entrance.
  • Return the entrance in O(n) time and O(1) space.

Complexity and Wrap-up

Summarizes the cost of Floyd's two-phase pointer algorithm.

Complexity analysis
Time
O(n)
Space
O(1)
Where the time goes
  • Cycle detection walkSlow and fast traverse a bounded tail and cycle.dominantO(n)
  • Cycle entrance walkTwo equal-speed pointers move to the entrance.dominantO(n)
  • Pointer storageOnly a constant number of indices is maintained.O(1)
How it grows
input size n →opsO(n²)O(n log n)O(n)O(log n)O(1)
Roughly what that costs
n101001,00010,000
O(n)101001K10K

Floyd's method meets the read-only, constant-space target while remaining linear in the input size.

Now try it on your own problem

Paste any LeetCode problem — or one of your own — and codebrew builds a walkthrough like this one for it.

Build a lesson from any problem

Related problems