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.
class Solution {
public:
/*algorithm; counting
time O(n) space O(n)
*/
int findDuplicate(vector<int>& nums) {
int n = nums.size();
vector<int>cnt(n,0);
for(int i = 0;i < n;i++){
cnt[nums[i]]++;
}
for(int i = 1;i < cnt.size();i++){
if(cnt[i] > 1)return i;
}
}
};
class Solution {
public:
/*algorithm; counting,but reuse nums array instead of allocate new array
time O(n) space O(1) [1,1,2]-->[1,-1,2]-->[0,-2,2]-->[0,-2,-1]
*/
int findDuplicate(vector<int>& nums) {
for(int i = 0;i < nums.size();){
if(nums[i] > 0){
int j = nums[i];
if(j==nums[j]){
nums[j] = -1;
continue;
}
if(nums[j] > 0){
swap(nums[i],nums[j]);
}else{
nums[j] += -1;
nums[i] = 0;
++i;
}
}else{
++i;
}
}
for(int i = 0;i < nums.size();i++){
if(nums[i] < -1){
return i;
}
}
}
};
class Solution {
public:
/*algorithm Pigeonhole principle
time O(n) space O(1)
*/
int findDuplicate(vector<int>& nums) {
int l = 0,h = int(nums.size());
while(l < h){
int m = l + (h-l)/2;
int cnt = 0;
for(int k = 0;k < nums.size();k++){
if(nums[k] <= m)
cnt++;
}
if(cnt > m)
h = m;
else
l = m+1;
}
return l;
}
};
class Solution {
public:
/*algoritm fast slow pointer , simliar to list cycle issue
we can create i -->nums[i] mapping
time O(n) space O(1)
[1,2,1]-->0->1->2->1
*/
int findDuplicate(vector<int>& nums) {
int fast = 0,slow = 0;
do{
slow = nums[slow];
fast = nums[nums[fast]];
}while(slow != fast);
int dup = 0;
while(dup != slow){
dup = nums[dup];
slow = nums[slow];
}
return dup;
}
};