Given an array of integers nums containing n + 1 integers where each integer is in the range [1, n] inclusive.
There is only one repeated number in nums, return this repeated number.
You must solve the problem without modifying the array nums and uses only constant extra space.
Input: nums = [1,3,4,2,2]
Output: 2
Input: nums = [3,1,3,4,2]
Output: 3
Input: nums = [3,3,3,3,3]
Output: 3
Key Constraints:
Brilliant Insight: Treat array as a linked list!
Why there's always a cycle:
This is a Floyd's Cycle Detection (Tortoise & Hare) problem:
def findDuplicate(self, nums):
# Phase 1: Find intersection point in cycle
slow = fast = nums[0]
while True:
slow = nums[slow] # Move 1 step
fast = nums[nums[fast]] # Move 2 steps
if slow == fast:
break
# Phase 2: Find entrance to cycle (duplicate)
slow = nums[0]
while slow != fast:
slow = nums[slow]
fast = nums[fast]
return slow
Why it works:
For nums = [1,3,4,2,2]:
Array as "Linked List":
Index: 0 1 2 3 4
Value: 1 3 4 2 2
Pointers from index to nums[index]:
0 → 1 → 3 → 2 → 4 → 2 (cycle back to 2)
Phase 1: Find meeting point
slow: 0 → 1 → 3 → 2 → 4
fast: 0 → 3 → 4 → 3 → 2 → 2
Meet at index 2 (value 4)
Phase 2: Find entrance
slow: 0 → 1 → 3 → 2
fast: 4 → 2 → 4 → 2
Both reach index 2 → duplicate is 2
[2,1,2] → 2[3,3,3,3,3] → 31class Solution {
2 public int findDuplicate(int[] nums) {
3 // Floyd's Cycle Detection (Tortoise and Hare)
4
5 // Phase 1: Find intersection point in the cycle
6 int slow = nums[0];
7 int fast = nums[0];
8
9 do {
10 slow = nums[slow]; // Move 1 step
11 fast = nums[nums[fast]]; // Move 2 steps
12 } while (slow != fast);
13
14 // Phase 2: Find the entrance to the cycle (duplicate number)
15 slow = nums[0];
16 while (slow != fast) {
17 slow = nums[slow];
18 fast = nums[fast];
19 }
20
21 return slow;
22 }
23}
24
25
26// Alternative Solution 1: Binary Search on Answer Range
27class SolutionBinarySearch {
28 public int findDuplicate(int[] nums) {
29 int left = 1;
30 int right = nums.length - 1;
31
32 while (left < right) {
33 int mid = left + (right - left) / 2;
34
35 // Count how many numbers are less than or equal to mid
36 int count = 0;
37 for (int num : nums) {
38 if (num <= mid) {
39 count++;
40 }
41 }
42
43 if (count > mid) {
44 // Duplicate is in [left, mid]
45 right = mid;
46 } else {
47 // Duplicate is in [mid + 1, right]
48 left = mid + 1;
49 }
50 }
51
52 return left;
53 }
54}
55
56
57// Alternative Solution 2: Marking with Negation (Modifies Array)
58class SolutionMarking {
59 public int findDuplicate(int[] nums) {
60 // Note: This modifies the array, violates constraint
61 for (int num : nums) {
62 int idx = Math.abs(num);
63 if (nums[idx] < 0) {
64 return idx;
65 }
66 nums[idx] = -nums[idx];
67 }
68
69 return -1;
70 }
71}
72
73
74// Alternative Solution 3: HashSet (Uses O(n) Space)
75class SolutionHashSet {
76 public int findDuplicate(int[] nums) {
77 // Note: This uses O(n) space, violates constraint
78 Set<Integer> seen = new HashSet<>();
79
80 for (int num : nums) {
81 if (seen.contains(num)) {
82 return num;
83 }
84 seen.add(num);
85 }
86
87 return -1;
88 }
89}
90