题目描述
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
思路一:采用辅助数组arr,对已出现的数进行标记;时间复杂度、空间复杂度均为O(N)。
代码一:
class Solution {
public:
// Parameters:
// numbers: an array of integers
// length: the length of array numbers
// duplication: (Output) the duplicated number in the array number
// Return value: true if the input is valid, and there are some duplications in the array number
// otherwise false
bool duplicate(int numbers[], int length, int* duplication) {
if (length == 0 || numbers == NULL)
return false;
vector<bool> arr(length, false); //用bool数组作为标志数组,比用int数组更节省空间
for(int i = 0; i < length; ++i) {
if(arr[numbers[i]]) {
*duplication = numbers[i];
return true;
} else {
arr[numbers[i]] = true;
}
}
return false;
}
};
思路二:由于题目没有要求需要保存原有数组不变,且数组内的数均小于n,因此可以在访问一个数后,将以该数为索引下标的数加上n;继续往后循环,若索引值大于n,则减n即为真实索引值;再以索引值作为下标取数,若该数大于n则表示之前已经出现过,此时返回索引值即可。
不需要额外的空间消耗,时间效率是O(n)
代码二:
class Solution {
public:
// Parameters:
// numbers: an array of integers
// length: the length of array numbers
// duplication: (Output) the duplicated number in the array number
// Return value: true if the input is valid, and there are some duplications in the array number
// otherwise false
bool duplicate(int numbers[], int length, int* duplication) {
if(length == 0 || numbers == NULL) {
return false;
}
int idx;
for(int i = 0; i < length; ++i) {
idx = numbers[i];
if(idx >= length) {
idx -= length;
}
if(numbers[idx] >= length) {
*duplication = idx;
return true;
} else {
numbers[idx] += length;
}
}
return false;
}
};
思路三:对数组进行重新排序,满足numbers[i]=i;从i=0开始循环,直到第一次出现需要交换的位置处已排好,即出现重复数,此时返回索引值即可,时间复杂度同样为O(N),空间复杂度为O(1)。
代码三:
class Solution {
public:
// Parameters:
// numbers: an array of integers
// length: the length of array numbers
// duplication: (Output) the duplicated number in the array number
// Return value: true if the input is valid, and there are some duplications in the array number
// otherwise false
void swape(int* i, int* j) {
int tmp = *i;
*i = *j;
*j = tmp;
}
bool duplicate(int numbers[], int length, int* duplication) {
if(length <= 0 || numbers == NULL) //数组为空、数组长度非正,返回false
return false;
for(int i = 0; i < length; ++i) { //数组内的数不在【0, n-1】范围内,返回false
if(numbers[i] < 0 || numbers[i] >= length)
return false;
}
int idx;
for(int i = 0; i < length; ++i) {
while(numbers[i] != i) { //确保当前下标i的索引值与i相等
idx = numbers[i];
if(numbers[idx] == idx) { //若索引值作为下标,对应地方满足上述要求,说明已找到重复数字
*duplication = idx;
return true;
} else { //若索引值作为下标,对应处不满足要求,则对这两个数进行交换
swape(&numbers[i], &numbers[idx]);
}
}
}
return false;
}
};