Find the Duplicate Number Solution
Given an array of n+1 integers in range [1, n], find the one repeated number โ without modifying the array and in O(1) extra space.
Problem Statement
Given an array nums containing n+1 integers where each integer is in the range [1, n] inclusive, there is exactly one repeated number. Find and return it. You must not modify the array and must use only O(1) extra space.
HashSet โ O(n) space
Traverse the array, adding each value to a set. If a value is already in the set, it's the duplicate. O(n) time but O(n) space โ violates the constraint.
index i points to nums[i]. The duplicate creates a cycle โ use Floyd's algorithm.
Floyd's Cycle Detection โ O(n) time, O(1) space
Treat the array as a function: f(i) = nums[i]. Starting from index 0, follow next = nums[current]. Since n+1 values map to n positions, by pigeonhole there's a cycle โ and the cycle's entry point is the duplicate value.
- Phase 1 โ Detect cycle: slow = nums[0], fast = nums[0]. Move slow by 1 hop, fast by 2. They meet inside the cycle.
- Phase 2 โ Find entry: Reset slow to nums[0]. Move both by 1 hop. They meet at the cycle entry = the duplicate.
- Start from index 0 (which is safe โ no value points to 0 since values are in [1,n]).
- The duplicate value X means two indices point to X, so X has two "incoming edges" โ creating a cycle entry.
- Floyd's phase 2 finds exactly this entry point.
Visual Walkthrough
Trace: nums = [1, 3, 4, 2, 2]. Index chain: 0โ1โ3โ2โ4โ2โ4โ... (cycle at 2).
Code โ Java & Python
Complexity Analysis
| Approach | Time | Space | Trade-off |
|---|---|---|---|
| HashSet | O(n) | O(n) | Violates space constraint |
| Sort | O(n log n) | O(1)* | Modifies array (*in-place sort) |
| Floyd's โ optimal | O(n) | O(1) | No modification, constant space |
Edge Cases & Pitfalls
| Case | Input | Why It Matters |
|---|---|---|
| Duplicate at start | [2, 2, 1] | Fast cycle entry detected quickly. |
| Many duplicates | [2, 2, 2, 2] | Duplicate appears n times. Floyd still finds 2. |
| Minimum | [1, 1] | n=1, chain: 0โ1โ1โ1... cycle at 1. |
nums[0] โ or starting from nums[0] in phase 2 and index 0 in phase 1. Phase 1: both start at nums[0]. Phase 2: one resets to nums[0] (not 0), the other stays at the meeting point. Consistency matters.