Difficulty: Medium · LeetCode 287
Problem
Given an array of integers nums containing n + 1 integers where each integer is in range [1, n], find the duplicate number without modifying array in O(1) space.
Understanding the problem
Map array indices to values as an implicit linked list: index -> nums[index].
Intuition
Treat array as implicit linked list. The duplicate number represents the entrance to a cycle. Apply Floyd's Cycle Detection in 2 phases.
Approach
Phase 1:
slow = nums[0],fast = nums[0]. Moveslow = nums[slow]andfast = nums[nums[fast]]until they meet.Phase 2: Reset
slow = nums[0]. Advance both pointers 1 step at a time until they meet at cycle entry point.Return entry point value.
Naive Solution — Brute Force
Use a hash set to track seen numbers.
class Solution:
def findDuplicate(self, nums):
seen = set()
for num in nums:
if num in seen:
return num
seen.add(num)
return -1class Solution {
public:
int findDuplicate(vector<int>& nums) {
unordered_set<int> seen;
for (auto num : nums) {
if (seen.count(num)) {
return num;
}
seen.insert(num);
}
return -1;
}
};class Solution {
public int findDuplicate(int[] nums) {
Set<Integer> seen = new HashSet<>();
for (int num : nums) {
if (seen.contains(num)) {
return num;
}
seen.add(num);
}
return -1;
}
}var findDuplicate = function(nums) {
const seen = new Set();
for (const num of nums) {
if (seen.has(num)) {
return num;
}
seen.add(num);
}
return -1;
};Time: O(n) · Space: O(n)
Optimized Code (Python 3)
class Solution:
def findDuplicate(self, nums):
slow = nums[0]
fast = nums[0]
while True:
slow = nums[slow]
fast = nums[nums[fast]]
if slow == fast:
break
slow = nums[0]
while slow != fast:
slow = nums[slow]
fast = nums[fast]
return slowclass Solution {
public:
int findDuplicate(vector<int>& nums) {
int slow = nums[0];
int fast = nums[0];
while (true) {
slow = nums[slow];
fast = nums[nums[fast]];
if (slow == fast) {
break;
}
}
slow = nums[0];
while (slow != fast) {
slow = nums[slow];
fast = nums[fast];
}
return slow;
}
};class Solution {
public int findDuplicate(int[] nums) {
int slow = nums[0];
int fast = nums[0];
while (true) {
slow = nums[slow];
fast = nums[nums[fast]];
if (slow == fast) {
break;
}
}
slow = nums[0];
while (slow != fast) {
slow = nums[slow];
fast = nums[fast];
}
return slow;
}
}var findDuplicate = function(nums) {
let slow = nums[0];
let fast = nums[0];
while (true) {
slow = nums[slow];
fast = nums[nums[fast]];
if (slow === fast) {
break;
}
}
slow = nums[0];
while (slow !== fast) {
slow = nums[slow];
fast = nums[fast];
}
return slow;
};Time: O(n) · Space: O(1)
Takeaway
Pattern — Array index mapping as Implicit Linked List Cycle Detection