You are given an array of integers nums containing n + 1 integers. Each integer in nums is in the range [1, n] inclusive.
Every integer appears exactly once, except for one integer which appears two or more times. Return the integer that appears more than once.
Example 1:
Input: nums = [1,2,3,2,2]
Output: 2Example 2:
Input: nums = [1,2,3,4,4]
Output: 4Follow-up: Can you solve the problem without modifying the array nums and using extra space?
Constraints:
1 <= n <= 10000nums.length == n + 11 <= nums[i] <= n
You should aim for a solution with O(n) time and O(1) space, where n is the size of the input array.
A naive approach would be to use a hash set, which takes O(1) time to detect duplicates. Although this solution is acceptable, it requires O(n) extra space. Can you think of a better solution that avoids using extra space? Consider that the elements in the given array nums are within the range 1 to len(nums).
We can use the given input array itself as a hash set without creating a new one. This can be achieved by marking the positions (0-indexed) corresponding to the elements that have already been encountered. Can you implement this?
We iterate through the array using index i. For each element, we use its absolute value to find the corresponding index and mark that position as negative: nums[abs(nums[i]) - 1] *= -1. Taking absolute value ensures we work with the original value even if it’s already negated. How can you detect duplicates?
For example, in the array [2, 1, 2, 3], where 2 is repeated, we mark the index corresponding to each element as negative. If we encounter a number whose corresponding position is already negative, it means the number is a duplicate, and we return it.
If we sort the array, any duplicate numbers will appear next to each other.
So after sorting, we just scan once and check if any two consecutive elements are equal.
The first equal pair we find is the duplicate.
0 to n - 2.i, check if nums[i] == nums[i + 1].-1.class Solution:
def findDuplicate(self, nums: List[int]) -> int:
nums.sort()
for i in range(len(nums) - 1):
if nums[i] == nums[i + 1]:
return nums[i]
return -1We can detect duplicates by remembering which numbers we have already seen.
As we scan the array, each new number is checked:
A set gives constant-time lookup, so this approach is simple and efficient.
seen.seen, return it (this is the duplicate).seen.-1.class Solution:
def findDuplicate(self, nums: List[int]) -> int:
seen = set()
for num in nums:
if num in seen:
return num
seen.add(num)
return -1Since the values in the array are from 1 to n, we can use an array to track whether we’ve seen a number before.
Each number directly maps to an index (num - 1).
This avoids using a hash set while still providing fast lookups.
seen of size n filled with zeros.num in the input array:seen[num - 1] is already set to 1.num (duplicate found).seen[num - 1] = 1.-1 if no duplicate is found (though the problem guarantees one).class Solution:
def findDuplicate(self, nums: List[int]) -> int:
seen = [0] * len(nums)
for num in nums:
if seen[num - 1]:
return num
seen[num - 1] = 1
return -1Since every value is between 1 and n, each number corresponds to an index in the array (num - 1).
We can use the array itself as a marking tool:
This method avoids extra memory and uses the input array as a tracking structure.
num in the array.idx = abs(num) - 1.nums[idx] is already negative:abs(num).nums[idx] by -1.-1.class Solution:
def findDuplicate(self, nums: List[int]) -> int:
for num in nums :
idx = abs(num) - 1
if nums[idx] < 0 :
return abs(num)
nums[idx] *= -1
return -1This method uses binary search on the value range, not on the array itself.
If all numbers from 1 to mid appeared at most once, then the count of numbers ≤ mid should be ≤ mid.
But if the count is greater than mid, it means the duplicate must be in the range [1, mid], because too many numbers fall into that range.
So we repeatedly:
≤ mid.Eventually, low == high, and that value is the duplicate.
low = 1 and high = n - 1 (value range).low < high:mid = (low + high) // 2.≤ mid.[low, mid], so set high = mid.[mid + 1, high], so set low = mid + 1.low is the duplicate.low.class Solution:
def findDuplicate(self, nums: List[int]) -> int:
n = len(nums)
low, high = 1, n - 1
while low < high:
mid = low + (high - low) // 2
lessOrEqual = sum(1 for num in nums if num <= mid)
if lessOrEqual <= mid:
low = mid + 1
else:
high = mid
return lowEvery number from 1 to n−1 should appear exactly once, but in the array, one number appears twice.
So for each bit position, we compare:
1 to n-1.If a bit appears more times in the array than expected, that bit must belong to the duplicate number.
By combining all such bits, we reconstruct the duplicate.
res = 0 to build the duplicate number bit by bit.b from 0 to 31:mask = 1 << b.nums have this bit set → call it x.1 to n−1 should have this bit set → call it y.x > y, it means the duplicate has this bit set, so add it to the answer:res |= mask.res.class Solution:
def findDuplicate(self, nums: List[int]) -> int:
n = len(nums)
res = 0
for b in range(32):
x = y = 0
mask = 1 << b
for num in nums:
if num & mask:
x += 1
for num in range(1, n):
if num & mask:
y += 1
if x > y:
res |= mask
return resTreat the array like a linked list, where each index points to the next index given by its value.
Because one number is duplicated, two indices will point into the same chain, creating a cycle — exactly like a linked list with a loop.
Using Floyd’s Fast & Slow Pointer technique:
Once they meet, we start a new pointer from the beginning:
slow = 0 and fast = 0.slow = nums[slow]fast = nums[nums[fast]]slow == fast.slow2 = 0.slow = nums[slow]slow2 = nums[slow2]class Solution:
def findDuplicate(self, nums: List[int]) -> int:
slow, fast = 0, 0
while True:
slow = nums[slow]
fast = nums[nums[fast]]
if slow == fast:
break
slow2 = 0
while True:
slow = nums[slow]
slow2 = nums[slow2]
if slow == slow2:
return slow