剑指offer算法题2
数组中重复的数字
题目描述
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
解题思路1:
由于所有数字都在 0~n-1 之间,因此,当一个数字被访问过后,可以设置对应位上的数 + n,之后再遇到相同的数时,会发现对应位上的数已经大于等于n了,那么直接返回这个数即可。
代码实现:
class Solution {
public:
bool duplicate(int numbers[], int length, int* duplication) {
for(int i=0;i<length;i++){
int j=numbers[i]%length;
numbers[j]+=length;
if(numbers[j]>=(2*length)){
*duplication = numbers[j]%length;
return true;
}
}
return false;
}
};
优点:算法复杂度低:时间算法复杂度
O(n)
O
(
n
)
,不需要额外空间。
缺点:可能出现溢出情况,对原数组进行了修改。
解题思路2:
使用长度为n的记录数组 ,初始值设为0, 遍历原数组,每个数字都在记录的数组上+1,若记录数组上的该数字已经等于1,返回该数。
代码实现:
class Solution {
public:
bool duplicate(int numbers[], int length, int* duplication) {
int temp[length];
memset(temp, 0, sizeof(temp));
// 局部数组没有默认值,如果声明的时候不定义,则会出现随机数。
for(int i=0;i<length;i++){
temp[numbers[i]]++;
if(temp[numbers[i]] >1){
*duplication = numbers[i];
return true;
}
}
return false;
}
};
优点:时间算法复杂度
O(n)
O
(
n
)
,不改变原数组。
缺点:空间复杂度高,需要
O(n)
O
(
n
)
。
解题思路3
从头到位扫描数组,当扫描到下标为i的数字m时,如果是,则扫描下一个数字;如果不是,则那它和第m个数字比较:如果相等,就返回这个重复的数字,如果不相等,就把第i个数字和第m个数字交换。
例子:
{2,3,1,0,2,5,3}
第0个和第2个比较,交换
{1,3,2,0,2,5,3}
第0个和第1个比较,交换
{3,1,2,0,2,5,3}
第0个和第3个比较,交换
{0,1,2,3,2,5,3}
第0个是0,第1个是1,第2个是2,第3个是3
第4个是2,第2个也是2,找到重复数字,返回
代码实现:
class Solution {
public:
bool duplicate(int numbers[], int length, int* duplication) {
if(numbers == nullptr || length <= 0)
return false;
for(int i=0;i<length;i++){
if(numbers[i] < 0 || numbers[i] > length-1)
return false;
}
for(int i=0;i<length;i++){
while(numbers[i]!=i){
if(numbers[i] == numbers[numbers[i]]){
*duplication = numbers[i];
return true;
}
int tmp = numbers[i];
numbers[i] = numbers[tmp];
numbers[tmp] = tmp;
}
}
return false;
}
};
优点:算法复杂度低:时间算法复杂度
O(n)
O
(
n
)
,不需要额外空间;不会出现溢出情况。
缺点:对原数组进行了修改。