Problem Statement
Find the Duplicate Number
You are given an array of n+1 numbers. Every number is somewhere between 1 and n, and exactly one number shows up more than once. Your job is to find that repeated number. The catch: you are not allowed to change the array, and you can only use a tiny fixed amount of extra memory (no building a set or a counter list). The clever trick is to treat the array like a chain of arrows. Picture each number as an arrow pointing to a position: if you are standing at index i, the value nums[i] tells you where to jump next. So nums[i] points to nums[nums[i]], and so on. Because one value repeats, two different positions end up pointing to the same place. That makes the chain of arrows loop back on itself, forming a cycle (a loop you can walk around forever). The exact spot where the loop begins is the duplicate number. To find where a loop starts, we use Floyd's Tortoise and Hare, a cycle detection method that uses one slow walker and one fast walker. Think of a tortoise and a hare running around a circular track: the faster hare eventually laps the slow tortoise and they bump into each other.
Signals to notice
Brute force first
Sort and scan, or hash set but that costs extra memory. That instinct is useful because it follows the prompt literally, but it usually keeps revisiting work the problem is begging you to organize.
The key insight
Floyd's cycle detection: treat the array as a linked list where index i points to nums[i]. The duplicate creates a cycle. Use slow/fast pointers to find the cycle entry point. Once you hold onto the right piece of information from moment to moment, the problem feels less like trial and error and more like following a shape that was there all along.
Trace it on nums=[1,3,4,2,2]
init: slow=nums[0]=1, fast=nums[0]=1 P1 iter1: slow=nums[1]=3; fast=nums[nums[1]]=nums[3]=2 -> 3!=2, continue P1 iter2: slow=nums[3]=2; fast=nums[nums[2]]=nums[4]=2 -> 2==2, break (meet at 2) P2 reset: slow=nums[0]=1, fast stays 2 -> 1!=2 P2 iter1: slow=nums[1]=3; fast=nums[2]=4 -> 3!=4 P2 iter2: slow=nums[3]=2; fast=nums[4]=2 -> 2==2, stop return slow=2
What must stay true
Since there are n+1 values in range [1,n], the pigeonhole principle guarantees a duplicate. The duplicate value creates a cycle in the index-following graph — Floyd's algorithm finds the cycle entry. When you keep that truth intact, each local choice supports the larger solution instead of fighting it.
Shape of the loop
slow = fast = nums[0] repeat: slow = nums[slow]; fast = nums[nums[fast]] until slow == fast # Phase 1: find meeting point slow = nums[0] while slow != fast: slow = nums[slow]; fast = nums[fast] # Phase 2: walk to cycle entry return slow # the duplicate
Pseudocode only — the full worked solution lives in the Solution tab.
Easy way to go wrong
Not seeing the linked list analogy — arr[i] is the 'next' pointer. Starting from index 0, following these pointers eventually enters a cycle, and the cycle entry point is the duplicate. Most mistakes here are not about syntax; they come from losing track of what your state, pointer, or structure is supposed to mean.