数组中重复的数字
1、题目
在一个长度为n的数组里的所有数字都在0~n-1的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次,请找出数组中任意一个重复的数字。
例如,如果输入长度为7的数组{2, 3, 1, 0, 2, 5, 3},那么对应的输出是重复的数字2或者3。
输入参数:一个整数数组numbers,数组长度length,一个用于指向数组重复数字的指针duplication
输出参数:true 或 false
2、解题
这道题的关键在于如何在时间复杂度最优且不消耗空间的情况下找出重复数字。
该题目有三种解法:
- 对数组排序,再从头到尾扫描排序数组,时间复杂度为O(nlogn)
- 使用哈希表,扫描数组的同时判断哈希表里是否已经包含该数字。未包含,则加入哈希表;若已包含,则找到
- 扫描数组,对每一个数组元素,不断与下标为元素值的数组元素交换,直至下标等于数组元素值为止。
第三种解法的具体步骤如下:
-
从头到尾依次扫描这个数组中的每个数字。
-
当扫描到下标为i的数字时,首先比较这个数字(用m表示)是不是等于i。
-
如果是,则接着扫描下一个数字
-
如果不是,则再拿它和第m个数字进行比较。
- 如果它和第m个数字相等,就找到了一个重复的数字(该数字在下标为i和m的位置都出现了)
- 如果它和第m个数字不相等,就把第i个数字和第m个数字交换,把m放到属于它的位置。
-
接下来再重复这个比较、交换的过程,直到我们发现一个重复的数字。
-
3、代码
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) {
//若相等,给指针赋值,返回true
if (numbers[i] == numbers[numbers[i]]) {
*duplication = numbers[i];
return true;
}
//若不等,则进行交换
int temp = numbers[i];
numbers[i] = numbers[temp];
numbers[temp] = temp;
}
}
//最后返回false
return false;
}
4、注意点
-
注意题目给出的数组的元素大小的范围为 [0, n-1]
-
注意开头的鲁棒性检查,包括
参数验证
和数组元素的大小
验证 -
找到重复元素后,记得给*duplication赋值并返回true