Problem Description:
Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.
Note:
You must not modify the array (assume the array is read only).
You must use only constant, O(1) extra space.
Your runtime complexity should be less than O(n2).
There is only one duplicate number in the array, but it could be repeated more than once.
Analysis :
1. Binary Search O(nlogn) solution
Find the mid in the integer range, traverse the nums count the digit not greater than the mid.
if (count <= mid) the dups digit occurs in the right half;
else the dups in the left half.
int findDuplicate(vector<int>& nums) {
int n = nums.size();
int l = 0, r = n - 1;
while (l < r)
{
int m = l + ((r - l) >> 1);
int count = 0;
for (int i = 0; i < n; ++i)
{
if (nums[i] <= m)
count ++;
}
if (count <= m )
l = m + 1;
else r = m;
}
return l;
}```
2. Floyd's loop detection;
if the size of nums is n;
so the index range from [0...n - 1], the digit [1...n - 1];
We can define a function from the set {0,...n - 1} onto itself.
f(i) = A [i];
so the duplicated value corresponds to a pair of indices i != j, such that f(i)
= f(j), Our challenge ,therefore, is to find the pair(i, j).
because the f(0) != 0,it can't be in the cycle, so we can start from nums[0].
if we want to start from the end f(n - 1) might equal with n - 1, so we set the
f(n) = A[n] - 1;
Start from the 0;
```
int findDuplicate(vector<int>& nums)
{
int n = nums.size();
if(n <= 1) return -1;
int slow = nums[0], fast = nums[nums[0]];
while (slow != fast)
{
slow = nums[slow];
fast = nums[nums[fast]];
}
fast = 0;
while (fast != slow)
{
fast = nums[fast];
slow = nums[slow];
}
return slow;
}
Start from the end;
int findDuplicate(vector<int>& nums) {
int n = nums.size(), slow = n - 1, fast = n - 1;
do {
slow = nums[slow] - 1;
fast = nums[nums[fast] - 1] - 1;
} while (slow != fast);
fast = n - 1;
do {
slow = nums[slow] - 1;
fast = nums[fast] - 1;
} while (slow != fast);
return slow + 1;
}
Another tricky solution using O(1) space, Here is the Link
int findDuplicate(vector<int>& nums)
{
int n = -1;
for(int i = 0; i < nums.size(); i++) {
n = abs(nums[i]);
if(nums[n] < 0) {
break;
}
else {
nums[n] *= -1;
}
}
// for(int j = 0; j < nums.size(); j++) {
// nums[j] = std::abs(nums[j]);
// }
return n;
}
4.
We can count the sum of each 32 bits separately for the given array (stored in “b” variable) and for the array [1, 2, 3, …, n] (stored in “a” variable). If “b” is greater than “a”, it means that duplicated number has 1 at the current bit position (otherwise, “b” couldn’t be greater than “a”).
int findDuplicate(vector<int>& nums)
{
int n = nums.size() - 1, res = 0;
for (int p = 0; p < 32; ++p)
{
int bit = (1 << p), a = 0, b = 0;
for (int i = 0; i <= n; ++i)
{
if (i > 0 && (i & bit) > 0) ++a;
if ((nums[i] & bit) > 0) ++b;
}
if (b > a) res += bit;
}
return res;
}